[考试反思]0521省选模拟102:印象
Posted hzoi-deepinc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[考试反思]0521省选模拟102:印象相关的知识,希望对你有一定的参考价值。
又不知道在干啥了。在联考里忘交了,所以排名是假的。
看一眼$T1$就直接知道怎么做,但是要列一大堆一大堆的式子,所以想放在最后写。
$T2$比较水,不怎么用想,一小时做完。
然后$T3$是个仙人掌的板子题,由于仙人掌专题一直在被咕咕咕所以我一个仙人掌的题都没写过。
然后考场当场$yy$仙人掌的板子,$3.5h$最后也只是拿到了树和仙人球的部分分。
事实证明其实板子我已经完全$yy$出来了,只不过有一个细节出了锅。。。。
再也不想干考场$yy$板子这种事了。。。。拿三四个小时干别人一小时不到的活然后还容易炸心态
平时再也不要留坑了遇到啥学啥肯定是没问题的
T1:island
大意:有一个四联通快共$n$行,每行上是一段连续的区间$[l_i,r_i]$。求所有点对距离和。$n le 10^6,10^9 le l_i le -1 ,1 le r_i le 10^9$
讨论一下有哪些路径以及怎么计算贡献:
所有路径的纵坐标差。直接对于每一行维护 上方所有点到当前行的距离,上方点个数。下方同理。扫一遍递推下来就可以。
跨过中线的横坐标差。对于每一行的左侧点考虑走到所有的右侧点右侧到左侧同理。大概是$frac{r(r+1)}{2} cnt_{left}$
不过中线的横坐标差。暴力枚举两行算贡献的话,发现答案与区间$min$有关。两种情况:(只考虑$i$走到$j$之前的横坐标变化)
首先为了走到$j$行的高于$min$的部分,所有点都要走到恰好$min$的位置$r_j-min$次,每一次的代价就是等差数列求和。
走到低于$min$的部分,那么高于$min$的第$i$行部分要先走到$min$位置,等差数列求和。低于$min$的直接走,二次等差数列求和。
每一部分都很好算。做单调栈维护出最小值控制区间,再用等差数列求和公式优化每一部分就行了。$O(n)$
公式要短一点不然常数硬核破百。及时合并同类项。
1 #include<cstdio> 2 #define ll long long 3 const int S=1000005,mod=998244353; 4 int min(int a,int b){return a<b?a:b;} 5 int mo(int x){return x>=mod?x-mod:x;} 6 void add(int&a,int b){a+=b;a-=a>=mod?mod:0;} 7 void dec(int&a,int b){a-=b;a+=a<0?mod:0;} 8 int d2(int a){return a*499122177ll%mod;} 9 int l[S],r[S],len[S],n,ans; 10 int cal2(int x){return (x+1ll)*x/2%mod;} 11 int cal3(int x){return (x+x+1ll)*(x+1)%mod*x%mod*166374059%mod;} 12 int in(int n,int r){add(ans,cal2(n-1)*1ll*r%mod);add(ans,cal3(n-1)*1ll*r%mod);} 13 void solve(int*a){ 14 static int sta[S],l[S],r[S],top,tot[S],tot2[S]; 15 for(int i=1;i<=n+1;++i){while(a[sta[top]]>a[i])r[sta[top--]]=i-1;sta[++top]=i;} 16 for(int i=n;~i;--i){while(a[sta[top]]>=a[i]&&top)l[sta[top--]]=i+1;sta[++top]=i;} 17 for(int i=1;i<=n;++i)in(a[i],2ll*(i-l[i]+1)*(r[i]-i+1)%mod-1); 18 for(int i=1;i<=n;++i)tot[i]=mo(tot[i-1]+a[i]),tot2[i]=(tot2[i-1]+1ll*a[i]*a[i])%mod; 19 for(int i=1;i<=n;++i) 20 add(ans,2ll*cal2(a[i]-1)*mo(( 21 (tot[i-1]-tot[l[i]-1]-1ll*a[i]*(i-l[i]))%mod*(r[i]-i+1)+ 22 (tot[r[i]]-tot[i]-1ll*a[i]*(r[i]-i))%mod*(i-l[i]+1) 23 )%mod+mod)%mod), 24 add(ans,mo(( 25 (tot2[r[i]]-tot2[i-1]+(tot[r[i]]-tot[i-1])*(1ll-a[i]-a[i])+a[i]*(a[i]-1ll)%mod*(r[i]-i+1))%mod*(tot[i]-tot[l[i]-1])+ 26 (tot2[i]-tot2[l[i]-1]+(tot[i]-tot[l[i]-1])*(1ll-a[i]-a[i])+a[i]*(a[i]-1ll)%mod*(i-l[i]+1))%mod*(tot[r[i]]-tot[i-1]) 27 )%mod+mod)); 28 } 29 int main(){ 30 scanf("%d%*s",&n); 31 for(int i=1;i<=n;++i)scanf("%d%d",&l[i],&r[i]),l[i]=-l[i],len[i]=mo(l[i]+r[i]); 32 int up=0,dw=0,upv=0,dwv=0; 33 for(int i=1;i<=n;++i)add(dw,len[i]),add(dwv,1ll*len[i]*i%mod); 34 for(int i=1;i<=n;++i)dec(dwv,dw),dec(dw,len[i]),add(ans,1ll*len[i]*mo(upv+dwv)%mod),add(up,len[i]),add(upv,up); 35 int totL=0,totR=0; 36 for(int i=1;i<=n;++i)add(totL,l[i]),add(totR,r[i]); 37 for(int i=1;i<=n;++i)add(ans,2ll*totL*cal2(r[i])%mod),add(ans,2ll*totR*cal2(l[i]-1)%mod); 38 solve(l); solve(r); 39 printf("%d ",ans); 40 }
还有每次到了这种题都不应该忘记$skyh$的大神代码(狗头
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=1e6+7; 5 const int mod=998244353; 6 const int inv6=166374059; 7 int n,bit,top; ll A; 8 int l[N],r[N],suf[N],sum[N],cal[N],pro[N],sta[N],L[N],R[N]; 9 inline ll calc2(int n){ 10 return n*(n+1ll)%mod*(2*n+1)%mod*inv6%mod; 11 } 12 inline ll calc(int L,int R){ 13 return (R+L)*(R-L+1ll)/2%mod; 14 } 15 void build(const int L,const int mid,const int R){ 16 const register int rm=r[mid],lp=mid-L,rp=R-mid,cl=calc(L,mid),cr=calc(mid,R),cm=calc(1,rm); 17 (A+=((rm-1ll)*rm/2%mod*rm-calc2(rm-1))%mod*(2*(lp+1ll)*(rp+1ll)%mod-1)+(cr*(lp+1ll)-cl*(rp+1ll))%mod*rm%mod*rm+(sum[R]-sum[mid]-1ll*rp*rm)%mod*(-1ll*cl*rm%mod-(lp+1ll)*cm%mod)+(sum[mid]-sum[L-1]-1ll*(lp+1)*rm)%mod*(1ll*cr*rm%mod-(rp+1ll)*cm%mod-(sum[R]-sum[mid]-1ll*rm*rp)%mod*2*rm%mod)+(cal[R]-cal[mid]-1ll*cm*rp%mod+pro[R]-pro[mid-1]-1ll*cr*rm%mod)%mod*(rm+sum[mid-1]-sum[L-1])+(cal[mid]-cal[L-1]-cm*(lp+1ll)%mod+1ll*rm*cl%mod-pro[mid]+pro[L-1])%mod*(rm+sum[R]-sum[mid]))%=mod; 18 } 19 char cb[1<<20],*cs,*ct; 20 #define getchar() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<20,stdin),cs==ct)?0:*cs++) 21 inline int read(register int x=0,register bool f=0,register char ch=getchar()){ 22 for(;!isdigit(ch);ch=getchar()) f=ch==‘-‘; 23 for(; isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch^48); 24 return f?-x:x; 25 } 26 int main(){ 27 n=read(); read(); r[0]=1e9+7; 28 for(int i=1;i<=n;++i) l[i]=read(),r[i]=read(); 29 for(bit=1;bit<=n+1;bit<<=1); 30 for(int i=n;i;--i) suf[i]=(suf[i+1]+r[i])%mod; 31 for(int i=1;i<=n;++i) (A+=(l[i]*(l[i]+1ll)/2+1ll*l[i]*i)%mod*suf[i])%=mod; 32 for(int i=n;i;--i) suf[i]=(suf[i+1]+r[i]*(r[i]+2*i+1ll)/2)%mod; 33 for(int i=1;i<=n;++i) (A-=1ll*l[i]*suf[i])%=mod; 34 sta[top=0]=0; 35 for(int i=1;i<=n;++i){ 36 while(top&&r[i]<=r[sta[top]]) top--; 37 L[i]=sta[top]+1; sta[++top]=i; 38 } 39 sta[top=0]=n+1; 40 for(int i=n;i;--i){ 41 while(top&&r[i]<r[sta[top]]) top--; 42 R[i]=sta[top]-1; sta[++top]=i; 43 } 44 for(int i=1;i<=n;++i) sum[i]=(sum[i-1]+r[i])%mod,cal[i]=(cal[i-1]+calc(1,r[i]))%mod,pro[i]=(pro[i-1]+1ll*r[i]*i)%mod; 45 for(int i=1;i<=n;++i) build(L[i],i,R[i]); 46 for(int i=1;i<=n;++i) swap(l[i],r[i]),l[i]=-l[i],r[i]=-r[i]; 47 for(int i=n;i;--i) suf[i]=(suf[i+1]+r[i])%mod; 48 for(int i=1;i<=n;++i) (A+=(l[i]*(l[i]+1ll)/2+1ll*l[i]*i)%mod*suf[i+1])%=mod; 49 for(int i=n;i;--i) suf[i]=(suf[i+1]+r[i]*(r[i]+2*i+1ll)/2)%mod; 50 for(int i=1;i<=n;++i) (A-=1ll*l[i]*suf[i+1])%=mod; 51 sta[top=0]=0; 52 for(int i=1;i<=n;++i){ 53 while(top&&r[i]<=r[sta[top]]) top--; 54 L[i]=sta[top]+1; sta[++top]=i; 55 } 56 sta[top=0]=n+1; 57 for(int i=n;i;--i){ 58 while(top&&r[i]<r[sta[top]]) top--; 59 R[i]=sta[top]-1; sta[++top]=i; 60 } 61 for(int i=1;i<=n;++i) sum[i]=(sum[i-1]+r[i])%mod,cal[i]=(cal[i-1]+calc(1,r[i]))%mod,pro[i]=(pro[i-1]+1ll*r[i]*i)%mod; 62 for(int i=1;i<=n;++i) build(L[i],i,R[i]); 63 printf("%lld ",(A*2%mod+mod)%mod); 64 return 0; 65 }
T2:river
大意:你要前进$n$次,如果当前是第$i$天则前进一次要花$a_{i mod m}$天。你也可以等若干天之后再前进。求最少天数。$n,a_i le 10^9, mle 10^6$
挺弱智的。找到最小的$a$爆扫更新一下$a_{i}=min(a_{i+1}+1,a_i)$。然后模拟就行。找到循环节就跳。$O(m)$
1 #include<cstdio> 2 int min(int a,int b){return a<b?a:b;} 3 int a[1000000],n,m,mn=2e9,mnp,lt[1000000];long long ans,la[1000000]; 4 int main(){ 5 scanf("%d%d",&n,&m); 6 for(int i=0;i<m;++i)scanf("%d",&a[i]); 7 for(int i=0;i<m;++i)if(a[i]<mn)mn=a[i],mnp=i; 8 for(int i=mnp-1;~i;--i)a[i]=min(a[i],a[i+1]+1); 9 a[m-1]=min(a[m-1],a[0]+1); 10 for(int i=m-2;i>mnp;--i)a[i]=min(a[i],a[i+1]+1); 11 for(int i=n-1,p=0;i>=0;--i){ 12 if(lt[p]&<[p]!=i+1)ans+=1ll*i/(lt[p]-i-1)*(ans-la[p]),i%=lt[p]-i-1; 13 p=(ans+=a[p])%m;if(!lt[p])lt[p]=i,la[p]=ans; 14 }printf("%lld ",ans); 15 }
T3:cac
大意:仙人掌。支持单点查询,以及所有在$(u,v)$路径上的点权值$+x$(同一个点在多个路径上算一次)。$n le 5 imes 10^5,q le 10^5$
大约是圆方树模板题。可以树上差分。
大体来说修改的时候要考虑$lca$如果是圆点就往上跳一个。并且开一个额外的数组维护作为$lca$而产生的贡献和。
查询的时候解个方程就知道查的是父节点的子树和-这个权值。$O(qlogn)$
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 const int S=1888888,mod=998244353; 5 vector<int>bl[S]; 6 int f[S],son[S],dep[S],sz[S],top[S],dfn[S],fir[S],l[S],to[S],ec,tim,T[S],dfr[S],n,ex[S]; 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 f[p]=fa; sz[p]=1; dep[p]=dep[fa]+1; 10 for(int i=fir[p];i;i=l[i])if(to[i]!=fa){ 11 Dfs(to[i],p),sz[p]+=sz[to[i]]; 12 if(sz[son[p]]<sz[to[i]])son[p]=to[i]; 13 } 14 } 15 void DFS(int p,int tp){ 16 top[p]=tp; dfn[p]=++tim; 17 if(son[p])DFS(son[p],tp); 18 for(int i=fir[p];i;i=l[i])if(!dfn[to[i]])DFS(to[i],to[i]); 19 dfr[p]=tim; 20 } 21 int Fir[S],L[S],To[S],Ec,d[S],pc,nt[S]; 22 void Link(int a,int b){L[++Ec]=Fir[a];Fir[a]=Ec;To[Ec]=b;d[a]++;} 23 void dfs(int p,int fa){ 24 f[p]=fa; dep[p]=dep[fa]+1; 25 for(int i=Fir[p],y;y=To[i];i=L[i])if(y!=fa) 26 if(!dep[y])dfs(y,p); 27 else if(dep[y]<dep[p]){ 28 pc++;int z=p; nt[y]--; nt[p]++; 29 do bl[z].push_back(pc),z=f[z];while(z!=y); bl[y].push_back(pc); 30 } 31 } 32 void DFs(int p,int fa){ 33 for(int i=Fir[p],y;y=To[i];i=L[i])if(dep[y]==dep[p]+1)DFs(y,p),nt[p]+=nt[y]; 34 if(!nt[p]&&fa)pc++,bl[p].push_back(pc),bl[fa].push_back(pc); 35 } 36 int mo(int x){return x>=mod?x-mod:x;} 37 void add(int x,int v){for(;x<=tim;x+=x&-x)T[x]=mo(T[x]+v);} 38 int ask(int x,int a=0){for(;x;x^=x&-x)a=mo(a+T[x]);return a;} 39 void mdf(int x,int y,int v){ 40 add(dfn[x],v);add(dfn[y],v);v=mod-v; 41 while(top[x]!=top[y])if(dep[top[x]]>dep[top[y]])x=f[top[x]];else y=f[top[y]]; 42 if(dep[x]>dep[y])x^=y^=x^=y; add(dfn[x],v);if(x>n)x=f[x]; 43 if(f[x])add(dfn[f[x]],v); ex[x]=mo(ex[x]+mod-v); 44 } 45 int main(){ 46 int m,q; scanf("%d%d%d",&n,&m,&q); pc=n; 47 for(int i=1,a,b;i<=m;++i)scanf("%d%d",&a,&b),Link(a,b),Link(b,a); 48 dfs(1,0);DFs(1,0); 49 for(int i=1;i<=n;++i)for(int j=0;j<bl[i].size();++j)link(i,bl[i][j]),link(bl[i][j],i); 50 Dfs(1,0);DFS(1,1);f[1]=1; 51 for(int op,x,y,v,_=1;_<=q;++_){ 52 scanf("%d%d",&op,&x); 53 if(op)y=f[x],printf("%d ",mo(mo(mod+ask(dfr[y])-ask(dfn[y]-1))+ex[x])); 54 else scanf("%d%d",&y,&v),mdf(x,y,v); 55 } 56 }
以上是关于[考试反思]0521省选模拟102:印象的主要内容,如果未能解决你的问题,请参考以下文章