还行吧。至少不算炸。虽说这个分的确也不怎么样。
考试的时候觉得$T2$是个计数,部分分好像还挺多,应该可想。
然后在$T2$上刚了仨小时,因为做的题不够会的知识点也不够所以只有签到分。
$T1$的话贪心暴力随便写就是了用不到一个小时。
然而其实$T1$是最可想的一个。。。应该吧。。。
这种难度的题以目前水平想出一道可能就要几个小时,所以一场考试基本只能压一道题。
$T2$早就有了$36$分的思路,然而最关键的一步居然是个其他题的结论,听说过但没记住,于是就没了。
得亏$T3$是个恶心的原题,然而没有删,基本上也没人拿到分,所以没有被拉开差距。
得$T1$者得天下了。
下午改题,俩题加起来刚好一下午,然后晚上回去做了道大爷昨天讲的分治题。
然而点分治和树上分块还是一道题都没有写,$KDTree$和$CDQ$以及诸如此类的不少锅也还没有修。。。
然后又去补习$T2$的知识点,生成函数,多项式复合逆。有点抽象,还没有学完。
拿着$LNC$的$WC$课件啃生成函数解图论计数,也不是很明白。但愿明天能多听懂一些。
数学的确是块硬骨头啊。。。
T1:U.N.OWEN就是她吗?
大意:$n$堆石子,$m$次操作。每次操作要求$[l_i,r_i]$中取出$k_i$石子。不够则尽量多的取。要求之前操作取的尽量多的前提下每次最多多少。
保证操作区间不包含。$n,m \le 300000$
看着题意就像贪心。
问题转化为二分图匹配(神一步):把需求排序后,需求和供应分别拆出等于石子数量的点,然后是二分图最大匹配。
运用$Hall$定理。因为询问不包含,所以相交的询问可以合并成一个大的再进行匹配,同理也就不必考虑子集。
首先把不被任何询问包含的石子扔掉,不然前缀和会出问题。
设石子数的前缀和数组为$A$。设排序后前$i$个询问拿的石子数是$B_j$。
有对于任意$i<j,B_i - B_{j-1} \le A_{r_j} -A_{l_{i}-1}$。移项。$C_j = B_{j-1} - A_{r_j},D_i= B_i - A_{l_{i}-1}$
这样与$i,j$相关的就分别移动到一边了。也即对于任意$i<j$要求$C_j \le D_i$
前后缀关系,区间最值,询问是两个最值相减,询问结束后按照数组含义发现是后缀加。
每次操作时发现涉及变化的限制也就是$D[1,t] ,C[t,m]$
都是区间操作,线段树随便来就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 1234567 4 #define lc p<<1 5 #define rc lc|1 6 #define md (cl+cr>>1) 7 int C[S],D[S],lzc[S],lzd[S],n,m,a[S],o[S]; 8 struct qs{int l,r,o,k;friend bool operator<(qs a,qs b){return a.l<b.l;}}q[S]; 9 void up(int p){C[p]=max(C[lc],C[rc]);D[p]=min(D[lc],D[rc]);} 10 void down(int p){ 11 if(lzc[p])C[lc]+=lzc[p],C[rc]+=lzc[p],lzc[lc]+=lzc[p],lzc[rc]+=lzc[p],lzc[p]=0; 12 if(lzd[p])D[lc]+=lzd[p],D[rc]+=lzd[p],lzd[lc]+=lzd[p],lzd[rc]+=lzd[p],lzd[p]=0; 13 } 14 void build(int p,int cl,int cr){ 15 if(cl==cr){D[p]=-a[q[cl].l-1];C[p]=-a[q[cl].r];return;} 16 build(lc,cl,md);build(rc,md+1,cr);up(p); 17 } 18 void chgc(int l,int w,int p=1,int cl=1,int cr=m){ 19 if(cl>=l){C[p]+=w;lzc[p]+=w;return;} down(p); 20 if(l<=md)chgc(l,w,lc,cl,md);chgc(l,w,rc,md+1,cr); up(p); 21 } 22 void chgd(int l,int w,int p=1,int cl=1,int cr=m){if(l>m)return; 23 if(cl>=l){D[p]+=w;lzd[p]+=w;return;} down(p); 24 if(l<=md)chgd(l,w,lc,cl,md);chgd(l,w,rc,md+1,cr); up(p); 25 } 26 int askc(int l,int p=1,int cl=1,int cr=m){ 27 if(cl>=l)return C[p]; down(p); 28 return l<=md?max(askc(l,lc,cl,md),C[rc]):askc(l,rc,md+1,cr); 29 } 30 int askd(int r,int p=1,int cl=1,int cr=m){ 31 if(cr<=r)return D[p]; down(p); 32 return r>md?min(askd(r,rc,md+1,cr),D[lc]):askd(r,lc,cl,md); 33 } 34 int main(){ 35 cin>>n; 36 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 37 cin>>m; 38 for(int i=1;i<=m;++i)scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k),q[i].o=i; 39 sort(q+1,q+1+m); 40 for(int i=2;i<=m;++i)if(q[i-1].r<q[i].l)for(int j=q[i-1].r+1;j<q[i].l;++j)a[j]=0; 41 for(int i=2;i<=n;++i)a[i]+=a[i-1]; 42 for(int i=1;i<=m;++i)o[q[i].o]=i; 43 build(1,1,m); 44 for(int i=1,a;i<=m;++i)a=min(askd(o[i])-askc(o[i]),q[o[i]].k),printf("%d\n",a),chgc(o[i],a),chgd(o[i]+1,a); 45 }
T2:哈德曼的妖怪少女
生成函数,边双计数,多项式复合逆。知识点待补。
T3:平安时代的外星人
大意:网格图,边带权,若干特殊格子,求从左上角出发包住所有特殊格子的最短有向可自交环。$n,m \le 400$
需要把问题弄得形象化一点。我们需要给它圈起来,大概就是在不割断它们之间路径的情况下,从左上角走到左上角。
路径?最短路树啊!如果你最后的路径包住了整棵最短路树,那么一定把所有特殊点都包进去了。
而且可以证明,你最后的路径的确不会切断最短路树上的边。
所以现在问题是怎么包住它。
直接做不行,考虑拆点。每个格点依据网格分成左上左下右上右下4个点。
正常情况下它们之间可以0费直接到达,但是如果中间有树边就不行,否则会割断最短路树。
其余的在原网格边两侧的四个点,建上原图的边,边权不变即可。
数组大小值得研究,要注意边数是$400 \times 400 \times 4 \times 4$的。
然后从左上角格点的右上角出发到达左下角跑最短路就可以了。
代码稍微有点恶心。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 3688888 4 #define inf 1234567890123456789ll 5 int o[555][555],pc,n,m,k,nt[555][555],ec=1,fir[S],l[S],to[S],w[S],e[2][555][555]; 6 int al[555][555],X[S],Y[S],ban[2][555][555],pre[S],ok[S]; 7 long long dt[S]; priority_queue<pair<long long,int> >q; 8 void link(int a,int b,int v){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;w[ec]=v;} 9 void con(int a,int b,int v=0){if(ok[a]&ok[b])link(a,b,v),link(b,a,v);} 10 int O(int x,int y,int v){return o[x][y]<<2|v;} 11 int main(){ 12 scanf("%d%d",&n,&m); 13 for(int i=0;i<n;++i)for(int j=0;j<m;++j)scanf("%d",&nt[i][j]); 14 for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)o[i][j]=++pc,X[pc]=i,Y[pc]=j,ok[pc]=1; 15 for(int i=0;i<n;++i)for(int j=0;j<=m;++j)scanf("%d",&e[0][i][j]),con(o[i][j],o[i+1][j],e[0][i][j]); 16 for(int i=0;i<=n;++i)for(int j=0;j<m;++j)scanf("%d",&e[1][i][j]),con(o[i][j],o[i][j+1],e[1][i][j]); 17 for(int i=2;i<=pc;++i)dt[i]=inf; q.push(make_pair(0,1)); 18 while(!q.empty()){ 19 int p=q.top().second;long long d=-q.top().first;q.pop(); 20 if(d!=dt[p])continue; 21 for(int i=fir[p];i;i=l[i])if(dt[to[i]]>d+w[i])q.push(make_pair(-(dt[to[i]]=d+w[i]),to[i])),pre[to[i]]=p; 22 }al[0][0]=1; 23 for(int lx,ly,x,y,i=0;i<n;++i)for(int j=0;x=i,(y=j)<m;++j)if(nt[i][j])while(!al[x][y]) 24 lx=X[pre[o[x][y]]],ly=Y[pre[o[x][y]]],ban[y==ly][min(x,lx)][min(y,ly)]=1,al[x][y]=1,x=lx,y=ly; 25 for(int i=1;i<=pc;++i)fir[i]=0; ec=1; 26 for(int i=4;i<pc+1<<2;++i)ok[i]=1; 27 for(int i=0;i<n;++i)for(int j=0;j<m;++j)if(nt[i][j])ok[O(i,j,3)]=ok[O(i,j+1,2)]=ok[O(i+1,j,1)]=ok[O(i+1,j+1,0)]=0; 28 for(int i=0;i<=n;++i)for(int j=0;j<=m;++j){ 29 if(!ban[0][i][j])con(O(i,j,1),O(i,j,3)),con(O(i,j+1,0),O(i,j+1,2)); 30 if(!ban[1][i][j])con(O(i,j,2),O(i,j,3)),con(O(i+1,j,0),O(i+1,j,1)); 31 if(m^j)con(O(i,j,1),O(i,j+1,0),e[1][i][j]),con(O(i,j,3),O(i,j+1,2),e[1][i][j]); 32 if(n^i)con(O(i,j,2),O(i+1,j,0),e[0][i][j]),con(O(i,j,3),O(i+1,j,1),e[0][i][j]); 33 } 34 for(int i=1;i<=m;++i)con(O(0,i,0),O(0,i,1)); 35 for(int i=1;i<=n;++i)con(O(i,0,0),O(i,0,2)); 36 for(int i=4;i<pc+1<<2;++i)dt[i]=inf; q.push(make_pair(dt[5]=0,5)); 37 while(!q.empty()){ 38 int p=q.top().second;long long d=-q.top().first;q.pop(); 39 if(d!=dt[p])continue; 40 for(int i=fir[p];i;i=l[i])if(dt[to[i]]>d+w[i])q.push(make_pair(-(dt[to[i]]=d+w[i]),to[i])); 41 }cout<<dt[6]<<endl; 42 }
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12309849.html