手速是硬伤啊,T1线段树打完了离散化没打完(其实是时间不够放弃了),T2调了近2个小时,T3暴力没用脑子写爆了零,以后要注意一下了这个
T1
45分的线段树可以启发正解,这题重点考察线段树标记的下传,
设f[x]为x的懒标记,-1/0/1/2代表无标记/全为0/全为1/反转。
考虑懒标记的叠加:
初 新 末
0 0 0
0 1 1
0 2 1
1 0 0
1 1 1
1 2 0
2 0 0
2 1 1
2 2 -1
线段树分别维护0/1最小位置即可。
T2
枚举公共的选几个,之后贪心选择单个的,最后贪心找剩下的最小的若干个补齐即可。
我们发现公共的每加1,单个的必须选择分别都会少1,所以可以把它们加入线段树即可,
查询前缀即可。(附上query代码)
1 int query(int k,int l,int r,int x) 2 { 3 if(!x) return 0; 4 if(w[k]<=x) return sum[k]; 5 if(l==r) return x*l; 6 int mid=(l+r)>>1; 7 if(w[ls[k]]>=x) return query(ls[k],l,mid,x); 8 else return sum[ls[k]]+query(rs[k],mid+1,r,x-w[ls[k]]); 9 }
注意query时若到叶子节点还没返回那一定是这个val的个数大于要求的个数,直接返回val*x。
T3
设g[i][S]代表处理完i个人S集合中的苹果没被吃掉的概率是否为0
1> a[i]$in$S||b[i]$in$S g[i][S]=g[i-1][S∪{b[i]/a[i]}];
2> a[i]$in$S&&b[i]$in$S g[i][S]=0;
3> a[i]$ otin$S&&b[i]$ otin$S g[i][S]=g[i-1][S];
我们发现转移的来源都是单一的,所以我们可以枚举最后剩下的一个apple,O(m)dfs出它是否可行,以及它的垫背集合(必须剩下的)。
考虑如何统计答案:a,b同时存在的条件一定是g[a][Sa]=1&&g[b][Sb]=1&&Sa∩Sb=∅;
简单证明一下为什么是∅:
设Sa与Sb最先的交集为e,也就是说没有e时Sa∩Sb=∅;
首先刚开始的时候一定为空,假设Sa中c需要用e做垫背,Sb中d需要用e做垫背,根据先前所述,c!=d。
所以(c,e)(d,e)一定不是一个人,也就是e这个苹果被吃了两次,不合法。