[考试反思]0130省选模拟13:悔恨

0+30+20=50。rk8

关键在于:

T1写错个变量名挂了100分

kxkxkxkx(激动的语无伦次)

考试过程?上来看T1,一个比较裸的基环树dp,断开环上一条边之后大概就是一个稍加改动的最大独立集。

思路不难想,细节倒是有一点,考场上调啊调啊过了样例又手模了各种数据都过了两个半小时之后很开心就扔了。

然后看T2/3啥都不会,写了俩随机化就走了。

然而T3随机化+贪心是可以AC的。正确性不知道。。。没写。。。

最后还有5分钟回T1,突然发现T1可以不是基环树而是基环树森林???

啊修锅修锅5分钟生死时速改完了最后测了遍样例,过了。

md样例不是森林啊喂它就是个基环树啊!!!

结果有一个变量写错了,在全图联通的情况下不会错。

然后友善的数据里一棵树都没有,光荣爆零。

然而T2的随机化又交一遍,多了10分。这脸黒的。。。

考后一直认为T1恶心而没有改,然而直到晚上剩下两道题改完我拿回T1代码之后感觉变量名不太对劲。。。3分钟后就AC了。。。

考后改题极度不顺利。其实主要是顺序错了,上来直接奔着T2的正解去了,结果一下午都没弄出来。

晚饭前寻思着换一下思路于是去写T3,10分钟,1A。

然而在其他人视角看来:一下午没有AC。我也很难受啊啊啊(写个P正解$O(2^8 \times 8 \times n)$理论复杂度都能过为啥要写正解)

然而至少这一次不容易是被认为在颓废了。T2一道题50个提交记录也不是闹着玩的。。。

就这样吧。一整天在这个椅子上坐了多少个小时一动没动。。。修仙一样。。。

T1:同桌的你

题目大意:黑白点基环森林。选定边集,要求选定后每个点度数为1,最大化边数的基础上最大化连接异色点的边数。要求输出任意一种方案。$n \le 10^6$

先假如它们都联通,是一棵基环树的话,怎么做?

我不喜欢pair,所以我设异色边的贡献为1000002,同色边的贡献为1000001,最大化贡献。最后答案除1000001就是边数,模1000001就是异色边数。(然而要开long long)

这样之后就变成了带权匹配问题。

常用的对付基环树的思路就是断开环上的一条边剩下一棵树做问题,然后再单独考虑这条边的贡献。

于是断开这条边之后这就真的变成了最大树上带权匹配,直接dp就可以了。dp[0/1][p]表示这个点有没有被它儿子匹配时的最优值。

然后考虑拆掉的一条边的贡献,发现它的贡献与它所连接的两个点是否匹配有关。

比较方便的做法就是把其中一个点当作根,然后再开一个[0/1]维表示那个节点是否被选。特殊处理一个点,不算太麻烦。

至于要求输出方案。。。变化不大,记录一下如果这个点和它的某个儿子配对了,那它到底是和那个儿子配对的,然后就可以dfs下去了(不管是否与儿子配对了都往下搜就是了)。

至于不是基环树而是基环森林。。。当成多个基环树分别跑就好了。

然后这题就没了啊。就是有点细节难写了一点而已。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 2222222
 4 #define C cp[sp]
 5 int cp[S],n,sex[S],fir[S],l[S],to[S],ec,deg[S],q[S],T,t,sp,sel[2][S];long long tans,dp[2][2][S],ans;
 6 vector<int>v1,v2;
 7 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
 8 void dfs(int p,int fa){
 9     dp[0][0][p]=dp[1][0][p]=0;deg[p]=0;
10     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p);
11     for(int q=0;q<2;++q){
12         long long md=-123456789098765,tot=0;int mp=0;
13         for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
14             dp[q][0][p]+=max(dp[q][0][to[i]],dp[q][1][to[i]]);
15             if((to[i]!=sp||(to[i]==sp&&q==1))&&-max(dp[q][0][to[i]],dp[q][1][to[i]])+dp[q][0][to[i]]+1000001+(sex[p]^sex[to[i]])>md)
16                 md=-max(dp[q][0][to[i]],dp[q][1][to[i]])+dp[q][0][to[i]]+1000001+(sex[p]^sex[to[i]]),mp=to[i];
17         }if(mp)sel[q][p]=mp,dp[q][1][p]=dp[q][0][p]+md;
18     }if(p==sp)dp[1][0][p]=dp[0][0][p],dp[0][1][p]=-123456789098765;
19 }
20 void sch(int s1,int s2,int p,int fa=0){
21     if(p==sp&&s1==1&&s2==0)s1=0;
22     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)
23         if(s2&&to[i]==sel[s1][p])v1.push_back(p),v2.push_back(to[i]),sch(s1,0,to[i],p);
24         else sch(s1,dp[s1][0][to[i]]<dp[s1][1][to[i]],to[i],p);
25 }
26 int main(){//freopen("1.in","r",stdin);
27     cin>>T;while(T-->0){
28         t=sp=ans=0;memset(dp,0xa0,sizeof dp);for(int i=1;i<=n;++i)deg[i]=sel[0][i]=sel[1][i]=0;
29         cin>>n;for(int i=1;i<=n;++i)scanf("%d%d",&cp[i],&sex[i]),sex[i]--,deg[cp[i]]++;
30         for(int i=1;i<=n;++i)if(!deg[i])q[++t]=i;
31         for(int h=1;h<=t;++h){deg[cp[q[h]]]--;if(!deg[cp[q[h]]])q[++t]=cp[q[h]];}
32         reb:sp=0;
33         for(int i=1;i<=n;++i)if(deg[i])sp=i;
34         if(!sp)goto res;
35         for(int i=1;i<=n;++i)fir[i]=0;ec=0;
36         for(int i=1;i<=n;++i)if(i^sp)link(i,cp[i]),link(cp[i],i);
37         dfs(C,0);
38         tans=max(dp[0][0][C]+1000001+(sex[C]^sex[sp]),max(dp[1][0][C],max(dp[0][1][C],dp[1][1][C])));
39         if(tans==dp[0][0][C]+1000001+(sex[C]^sex[sp]))v1.push_back(C),v2.push_back(sp),sch(0,0,C);
40         else if(tans==dp[1][0][C])sch(1,0,C);
41         else if(tans==dp[1][1][C])sch(1,1,C);
42         else if(tans==dp[0][1][C])sch(0,1,C);
43         ans+=tans;
44         goto reb;
45         res:
46         cout<<ans/1000001<<‘ ‘<<ans%1000001<<endl;
47         for(int i=0;i<v1.size();++i)printf("%d %d\n",v1[i],v2[i]);
48         v1.clear();v2.clear();
49     }
50 }

T2:大水题

大意:坐标轴上n个点,每个点有颜色(一共8种)。求最长子段,两端点都是给定点,且段中至少有$k$种颜色,且每种出现过的颜色出现次数相同。$n \le 10^5$

优秀一点的暴力的话,运用到差分。考虑怎么应用出现的次数都相等这个性质。

做差之后都一样啊不久相等了吗?所以我们排序后扫一遍序列统计每种颜色出现次数的前缀和,每次枚举一个集合,然后做差哈希压状态,在每个点都更新一次答案或数组。

对于满足条件的段的两个端点,它们的哈希值是一样的。维护dp[s][hsh]表示到目前点为止,选定颜色集为s此时差分的哈希值为hsh的这种状态的最早出现位置。

要考虑到如果出现了一个选定点集中不包含的颜色,那么就要把对应的点集清空。

这样做的复杂度是$(8 \times 2^8 \times n)$。然而跑不满,极致卡常之后,就可以AC了。

细节倒是有不少。数据特别水动不动就WA90。什么哈希撞模撞进制,每次断开时要记得把桶清空,还要插一个哈希为0当前点的位置 。。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct cow{int x,c;friend bool operator<(cow a,cow b){return a.x<b.x;}}c[111111];
 4 vector<int>ve,v[1<<8];int cnt[9][111111],k,n,ans=-1,rj[1<<8],sc,sn[1<<8],C;
 5 struct hashmap{
 6     #define mo 10000003
 7     unsigned long long to[mo];int fir[mo],l[mo],v[mo],ec;
 8     int&operator[](unsigned long long x){
 9         int r=x%mo;
10         for(int i=fir[r];i;i=l[i])if(to[i]==x)return v[i];
11         l[++ec]=fir[r];fir[r]=ec;to[ec]=x;if(!l[ec])ve.push_back(r);return v[ec]=-1;
12     }
13     void clear(){
14         ec=0;for(int i=0;i<ve.size();++i)fir[ve[i]]=0;ve.clear();
15     }
16 }M;
17 unsigned long long m3[9];
18 int cal(int l,int r){
19     int c=0;
20     for(int i=1;i<=C;++i)c+=(cnt[i][r]-cnt[i][l]?1:0);
21     return c>=k;
22 }
23
24 int main(){//freopen("d.in","r",stdin);freopen("1.out","w",stdout);
25     cin>>n>>k;
26     for(int i=1;i<=n;++i)scanf("%d%d",&c[i].x,&c[i].c),cnt[c[i].c][i]++,C=max(C,c[i].c);
27     for(int i=1;i<=C;++i)for(int j=1;j<=n;++j)cnt[i][j]+=cnt[i][j-1];
28     for(int i=1;i<1<<C;++i){
29         int j,cb=1;
30         for(j=C;j;--j)if(i&1<<j-1)break;rj[i]=j;
31         for(j--;j;--j)if(i&1<<j-1)cb++,v[i].push_back(j);
32         if(cb>=k)sn[++sc]=i;
33     }
34     sort(c+1,c+1+n);
35     for(int q=1,s;s=sn[q],q<=sc;++q){
36         unsigned long long hsh=0,rt=1;for(int i=1;i<=C;++i)m3[i]=0;M.clear();M[0]=0;
37         for(int i=0;i<v[s].size();++i)m3[v[s][i]]=rt,rt*=311321;
38         for(int i=1;i<=n;++i)if(c[i].c==rj[s]){
39             unsigned long long p=1;while(p!=rt)hsh-=p,p*=311321;
40             if(M[hsh]!=-1)ans=max(ans,cal(M[hsh],i)*c[i].x-c[M[hsh]+1].x);
41             else M[hsh]=i;
42         }else if(m3[c[i].c]){
43             hsh+=m3[c[i].c];
44             if(M[hsh]!=-1)ans=max(ans,cal(M[hsh],i)*c[i].x-c[M[hsh]+1].x);
45             else M[hsh]=i;
46         }else M.clear(),M[0]=i,hsh=0;
47     }cout<<ans<<endl;
48 }

说一下尝试了一下午最后放弃了的正解。

不难发现每次枚举所有的256种状态明显有多余,考虑什么是真正有效的状态。

加入当前在点$i$,那么点$i-2$选了的话点$i-1$也一定选了,所以说这是单调的,往前走颜色的种数单调递增。

这样的话其实每个点的有效状态只有$8$个。

然后有一个细节不是很好处理,$skyh$比较忙丢给我一份代码我没看懂。。。所以只能自己口胡一个没写出来的。

就是你会发按照这样只枚举8种状态的话,现在某种奶牛出现的时候有一些状态丢失了。(例如样例,你在第7个点尝试更新答案时,你想找集合(1 2 3)却发现你在对应的第1个点处时并没有(1 2 3)这个集合)

怎么办?最简单粗暴的就是在更新每个状态时,把它的每一个超集也更新,但是这样复杂度是不对的。

然而一个可行的复杂度正确的方法是:如果一种颜色是第一次出现,那么就把所有已有状态(一定都不包含它,因为是第一次出现)都加上这种颜色,拷贝一遍。

这样就能解决上述问题了。因为最多只有8次这种操作所以复杂度不是问题。

然而实现起来挺恶心的,拷贝的时候需要处理哈希值的变化(插入了一种数),分类讨论什么的。。。非常麻烦于是没有写

T3:佛罗里达

大意:$n$点分成两部,$i,j$在同一部有$T_{i,j}$代价。最小化两部中最大代价的和。$n \le 250$

一眼网络流。错误直觉害人啊。

先扯扯随机化。

考虑一个贪心,我们依次考虑每个点,把它加入一个集合,让代价尽量小。

这显然是有后效性的,所以没有正确性。毕竟只是一个假贪心。

但是我们发现如果加入的点的顺序比较合适我们就能找到最优解。而且概率并不是很小(不会算也不会证)

所以我们把点随机排列进行贪心,单次复杂度是$O(n^2)$的。由于贪心的存在正确率还不错,所以就AC了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int mtx[255][255],v[255],n,ec,f[255],ans,q1[255],q2[255],f1,f2,t1,t2;
 4 struct ed{int a,b,v;friend bool operator<(ed x,ed y){return x.v<y.v;}}e[66666];
 5 int find(int p){return f[p]==p?p:f[p]=find(f[p]);}
 6 int main(){//freopen("1.in","r",stdin);
 7     int T=0;
 8     while(T++,cin>>n){
 9         for(int i=1;i<=n;++i)f[i]=i;ec=0;ans=2000000000;
10         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)scanf("%d",&mtx[i][j]),mtx[j][i]=mtx[i][j];
11         srand(time(0));
12         while(clock()*(3-T)<2900000){
13             random_shuffle(f+1,f+1+n);t1=t2=f1=f2=0;
14             for(int i=1;i<=n;++i){
15                 int fee1=f1,fee2=f2,p=f[i];
16                 for(int j=1;j<=t1;++j)fee1=max(fee1,mtx[p][q1[j]]);
17                 for(int j=1;j<=t2;++j)fee2=max(fee2,mtx[p][q2[j]]);
18                 if(fee1-f1>fee2-f2)f2=fee2,q2[++t2]=p;
19                 else f1=fee1,q1[++t1]=p;
20             }ans=min(ans,f1+f2);
21         }cout<<ans<<endl;
22     }
23 }

最后看了正解才发现它和我考场上的思路有多像。

首先这个东西让我们求最小值让人总想二分。但是因为有个加和所以不能直接搞。

因为数据范围不大,所以我们考虑枚举其中一部的贡献,再二分检查另一部。

所以问题转化为A部和B部的内部连边分别小于等于某个值是否可行。

根据边与这两个值的大小关系分类讨论,可以发现这个分部其实就是2SAT的模型。

总的权值数是$O(n^2)$的。单次处理是$O(n^2log)$的。所以总的复杂度是$O(n^4log)$的。

没多少分所以考场上没有写。只比暴力多了20分然而没剩下多少时间很可能调不出来。

这样枚举这种图上最大值的模型取值不会很多,在这道题里只有$O(n)$种。(不会证)

所以猜测是最大生成树上的边,根据题目定义发现这是对的。

跑最大生成树,然后进行黑白染色(这里考场上没有考虑到)。

如果一种划分同时包含了黑点与白点,那么它的取值就一定是最大生成树上的边了。

而如果它只包含了一种颜色的点,那么只有1种情况,特殊处理即可。

然后这样总的复杂度就下降到了$O(n^3log)$。看起来玄但是出题人说是可以过的。

然而考场上考虑的不全面,时间也不够,复杂度看起来也不对,就没敢写。

最近总是差不多想到正解还是没敢写啊。。。还是太菜了,继续加油啊。。。

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12244279.html

时间: 2024-08-26 17:33:51

[考试反思]0130省选模拟13:悔恨的相关文章

[考试反思]0113省选模拟6:过载

真累啊...离上次放假也挺久,离下次放假也挺久,离上次放出去玩也挺久,离下次放出去玩还不知道有多久... 好累啊...大脑基本成天在挂机了.什么也不想干了... 持续状态不佳.但是今天运气好,所以考试排名看起来还可以. T1没认真读题也没看数据范围,以为是送分题,17分钟写完交了...然后我就把分送出去了 像个弱智一样...但是现在的精神状态的确不太能支持好好做题 幸亏T2是个比较简单的SAM+dp,思维量不大,脑子宕机的时候也能写一写. (归功于当时给大家讲课时稍微有一点理解,要是其它的板子我

[考试反思]0114省选模拟7:迷离

这次考得相对不错,但是没什么水准. 只不过记得T1这道原题而已.虽说我忘了怎么做,而且数据范围不一样...差不多是从头想的. 但是并没有AC,像个弱智一样,有两个细节写的完全不对还有80分运气也是真好. 其实挂了不止两个细节...以为是原题于是上来就写20分钟写完,然后过一会出一个锅... 然后看T2,感觉$O(nk^2)$也许差不多?常数很大...但也不会别的.挺好想但是不是很好写. 于是乎强烈谴责cbx没素质暴力水题考后还不改正解的无脸行径 于是就开始写,写了一个半小时. 看T3,绝对大神题

[考试反思]0117省选模拟10:争夺

T3出了一点锅,于是按IOI赛制打的. 可能也是这辈子唯一一次好好打的IOI赛制了. 提答,又沉里面了,进去就出不来.莫名的虚荣让我根本没有回头看传统题. 于是的确在T3的80%时间里一直单题rk1,然而其实很慌,剩下两道题又怎样? 运气好,T1特别水,T2数据水,T3用奇技淫巧多拿7分于是并列rk1了. 数组没清空丢了1分... 状态差的不行,一下午一道题都没改出来...咕到第二天也没改出来 于是在第二天考试的时候写完三个暴力之后终于把T2A了... 然后第二天考试就炸了,没什么好说的 T1:

[考试反思]0220省选模拟27:怪异

怪异的一场考试.考的有点懵 $T1$正解是模拟,人人都能切,然而也没有多少人敢笃定这就是正解吧,常数和精度上下卡着,看运气的题了. $T2$想到了第二档分其实离正解就不远了但是时间不够没往下想.回$T1$卡常去了. $T3$不给状压分,于是猜到一条结论之后并不敢往下想... 然而最后$T1$也没有卡过,考后也在这破玩意上浪费了不少时间... 而且$T3$数据特别谁水暴力可以过,然而因为我不会决策点单调,所以学了学知识点,并没有用暴力水过... T1:飞行棋 大意:长度为$n$的序列,$m$人.每

[考试反思]0410省选模拟67:迷惑

现在想想,先做$T3$真乃人间迷惑行为. 部分分不多的一场考试,$T1$部分分最多结果没花时间光荣爆零,结果正解真的就是一个暴力+大力分类讨论 $T2$也比较可想,然而看着$75pts$的子任务心中有几分慌张,苟了个暴力跑路了. 结果一个弱智$T3$的$10pts$部分分$O(n^8)$暴写了$2.8k$.从这代码长度看是不是$10pts$您施舍的有点少啊. 其余部分分一点用没有,不知道咋想的. T1:链 大意:维护操作:加边,询问有几个点满足:删掉之后图中剩下的都是若干链.$n,m \le 2

[考试反思]1219省选模拟3: 释怀

有些东西渐渐就远去了...不必挂念. 只有时间才拥有如此力量.我们能做的,唯有释怀. 这次的题格外顺手,大概是我的强项了. 但是考得还是不够好吧...感觉可以更高的 今天迎来了学了OI一年多比较重要的一个成就:(虽说是在考后) AC1000道题!还是挺不容易的. 第1000道题是今天的T3.大部分是自己思考的,题也不是很简单,挺好的. 挺过了联赛,现在想要等到下一次整百,可能就要到3月份了. 我还能在OI多久呢? 回到这场考试. T1的数据范围只有10000,让我想起了ALO那道题50000数据

[考试反思]0110省选模拟5:信仰

又倒一啦 10分真是个熟悉的成绩(虽然没有爆零熟悉) 状态一直低迷,没什么好说的 答题策略的话...就那样吧 一眼看出T1是结论题,没有部分分,不好写. 但T2是伯努利数的差不多是模板题了,于是就奔着它去了. 没有注意$0^0=1$.过不去样例最后交的暴力 没有抽时间认真打T3的暴力,因为至多30分. 因为现在30分和0分对我来说是一样的.我是要靠着省选翻盘,拿大众分的话肯定还是退役,求个稳,4个月白学. 现在的答题策略的确不能像联赛时一样了.现在求稳是赢不了了,在稳住200和争取230里我可能

[考试反思]0122省选模拟12:延迟

博客咕过了一年我也就忘了我考试状态了2333. T1是弱智题但是没想...写个暴力跑路了(时间不够,主要投在T2/3上了) 然而其实想到了一个乱搞,觉得能得分的概率不大,结果数据奇水完全不对的玩意还有20分,然而我并没有写... 然而T2写的是正解,虽说没有其他人的状压优秀,T了一个细节WA了一个拿了80分,凑合吧. 然后T3时间不多的时候写的,拿个暴力,想到了正解大概怎么写但是没有写,太恶心. 考后改题写了写,一下午就过去了...一晚上也就过去了...弄得跟我颓废了半天一样... 然而是真xx

[考试反思]0201省选模拟15:分界

30+10+30+100=170 rk13 17岁的第一仗出师不利. 和外校联考,所以难度不高?后三道题非常简单基本上都是裸的. 但是我做的这是个啥啊... T2广义后缀自动机板子写挂,如果儿子是nq就把儿子修改成nq... T3想到正解然后算错复杂度结果觉得都可以写个简单的于是就把暴力交了上去. T1猜到了第一个结论不会分块暴力也没想到数位dp... 考试前就感觉今天要炸,结果就真炸了. 又当了一次改题大神.半小时一道,中午没睡觉就直接改完了. 下午在uoj上乱跑找好题做ppt.效率挺低的.