[考试反思]0207省选模拟20:风波
估分10+20+20=50。T1没炸T2炸了。总体来说炸得不算厉害。
开考的第一个小时一直在争论T1到底是不是原题。
管它是不是我按照原题的方法打呗(其实不太一样,更简单了但是数据范围加大时限减小)
一个LCT调了好久。。。至少最后还是调出来了,难得。。。(第一次在考场上调出LCT。。。虽说原来考场上也没写过)
T2特别简单但是看错题导致想到正解又放弃了而且写了错误题意下的暴力光荣爆零(样例就是个x啊)
T3的话是个单变量的题,惯性打表找规律,没有发现什么,但是根据函数增长速度隐约觉得答案是个低次多项式。
想代值求解来着但是觉得不靠谱,于是又错失了AC。。。(然而幸亏没A。。。这题正解太神奇了虽说就算看了正解也就是暴解的多项式。。)
然而今天改题效率奇高,中午就写完了简单的T2。(然而一个愚蠢的细节又调了半天)
然后下午又砸了两三个小时在昨天T2上终于是A了,一共用了差不多十个小时的题。。。那题解我得好好弄一弄了。。。
在skyh的讲解下弄明白了昨天T3,一个多小时也就写完了。就总算是把昨天的锅修了。
然后看了题解知道今天T3考场上的思路可行,随便写一写就A了。
然而T3题解的具体列式过程还有待仔细研究一下,但因为想到了昨天咕掉的反思于是今天优先来写反思了。(现在是18:43)
不出意外的话今晚把T3题解做法弄明白之后就去把根号数据结构的视频课收个尾差不多今天也就结束了。
昨天欠的状态差不多今天也就都补回来了啊。挺好的一天。
T1:Ring
大意:无向图,求第[l,r]条边是否组成环。$n,m,q \le 300000$
原题《GERALD07加强版》。稍加改动。
因为这题没有强制在线,所以这次写的比上次简单的多了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 666666 4 #define lc c[0][p] 5 #define rc c[1][p] 6 int c[2][S],f[S],q[S],lz[S],n,m,Q,lst[S],a[S],b[S],tf[S],mn[S],w[S]; 7 bool nr(int p){return c[0][f[p]]==p||c[1][f[p]]==p;} 8 void rev(int p){swap(lc,rc);lz[p]^=1;} 9 void down(int p){if(lz[p])lz[p]=0,rev(lc),rev(rc);} 10 void up(int p){mn[p]=min(p,min(mn[lc],mn[rc]));} 11 void spin(int p){ 12 int F=f[p],G=f[F],D=c[1][F]==p,B=c[!D][p]; 13 if(nr(F))c[c[1][G]==F][G]=p; c[!D][p]=F; c[D][F]=B; 14 if(B)f[B]=F; f[F]=p; f[p]=G; up(p); up(F); 15 } 16 void splay(int p){ 17 int F,r=p,top;q[top=1]=p; 18 while(nr(r))q[++top]=r=f[r]; while(top)down(q[top--]); 19 while(F=f[p],nr(p))spin(p);up(p); 20 } 21 void access(int p){int r=p;for(int y=0;p;p=f[y=p])splay(p),rc=y,up(p);splay(r);} 22 void make(int p){access(p);rev(p);} 23 void link(int a,int b){make(a);f[a]=b;} 24 void split(int a,int b){make(a);access(b);} 25 void cut(int a,int b){split(a,b);f[a]=c[0][b]=0;up(b);} 26 int find(int p){return tf[p]^p?tf[p]=find(tf[p]):p;} 27 void build(int p,int cl,int cr){ 28 if(cl==cr){w[p]=lst[cl];return;} 29 build(p<<1,cl,cl+cr>>1);build(p<<1|1,(cl+cr>>1)+1,cr);w[p]=max(w[p<<1],w[p<<1|1]); 30 } 31 int ask(int l,int r,int p,int cl,int cr){ 32 if(l<=cl&&cr<=r)return w[p]; 33 return max(l<=cl+cr>>1?ask(l,r,p<<1,cl,cl+cr>>1):0,r>cl+cr>>1?ask(l,r,p<<1|1,(cl+cr>>1)+1,cr):0); 34 } 35 int main(){//freopen("1.in","r",stdin); 36 scanf("%d%d%d",&n,&m,&Q);mn[0]=f[0]=n+m+1; 37 for(int i=1;i<=n;++i)tf[i]=i; 38 for(int i=1;i<=m;++i){ 39 scanf("%d%d",&a[i],&b[i]); 40 if(find(a[i])==find(b[i])){ 41 split(a[i]+m,b[i]+m);lst[i]=mn[b[i]+m]; 42 cut(lst[i],a[lst[i]]+m);cut(lst[i],b[lst[i]]+m); 43 }else tf[tf[a[i]]]=tf[b[i]]; 44 link(i,a[i]+m);link(i,b[i]+m); 45 }build(1,1,m); 46 for(int i=1,l,r;i<=Q;++i)scanf("%d%d",&l,&r),puts(ask(l,r,1,1,m)>=l?">_<":"QAQ"); 47 }
T2:Exchange
大意:维护序列支持区间加,区间交换,区间求和。区间交换的形式为$[l\times 2^c,(l+1)\times 2^c),[r \times 2^c,(r+1)\times 2^c)$。强制在线。$n\le 10^8,m\le 10^5$
考场上看区间交换形式时没有看到$l,r$也乘了$2^c$。然后就变得非常恶心。
看到之后就是很明显的$zkw$线段树的变版。利用了区间长度与区间左端点都是2的整次幂的倍数的性质。
类似$FFT$预处理的形式,如果n长度不是2的整次幂,就把它扩展到2的整次幂。
然后就是一个非常裸的动态开点线段树了。区间交换直接取值$swap$节点即可。
代码也极端好写。
同时也$get$到了一个新坑点。。。不强制在线时有时候$lastans \times =0$是有锅的。例如这题就算$lastans=0$你也会多取模一次。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 30000000 4 #define md (cl+cr>>1) 5 int rt,n,m,o,lc[S],pc,rc[S],lz[S],N;long long ans,w[S]; 6 void down(int p,int cl,int cr){ 7 if(!lc[p])lc[p]=++pc;if(!rc[p])rc[p]=++pc; 8 lz[lc[p]]+=lz[p];lz[rc[p]]+=lz[p]; 9 w[lc[p]]+=(md-cl+1ll)*lz[p];w[rc[p]]+=(cr-md+0ll)*lz[p];lz[p]=0; 10 } 11 void add(int l,int r,int v,int&p=rt,int cl=0,int cr=N){ 12 if(!p)p=++pc; 13 if(l<=cl&&cr<=r){lz[p]+=v;w[p]+=v*(cr-cl+1ll);return;} 14 if(lz[p])down(p,cl,cr); 15 if(l<=md)add(l,r,v,lc[p],cl,md); if(r>md)add(l,r,v,rc[p],md+1,cr); w[p]=w[lc[p]]+w[rc[p]]; 16 } 17 long long ask(int l,int r,int&p=rt,int cl=0,int cr=N){ 18 if(!p)p=++pc; 19 if(l<=cl&&cr<=r)return w[p]; 20 if(lz[p])down(p,cl,cr); 21 return (l<=md?ask(l,r,lc[p],cl,md):0)+(r>md?ask(l,r,rc[p],md+1,cr):0); 22 } 23 int&find(int l,int r,int&p=rt,int cl=0,int cr=N){ 24 if(!p)p=++pc; 25 if(l==cl&&cr==r-1)return p; 26 if(lz[p])down(p,cl,cr); 27 int&x=l<=md?find(l,r,lc[p],cl,md):find(l,r,rc[p],md+1,cr);w[p]=w[lc[p]]+w[rc[p]]; 28 return x; 29 } 30 int main(){ 31 cin>>n>>m>>o;N=(1<<27)-1; 32 for(int i=1,k,l,r,d;i<=m;++i){ 33 scanf("%d%d%d",&k,&l,&r);if(o)l=(l+ans)%(n+1),r=(r+ans)%(n+1); 34 if(k==3)printf("%lld\n",ans=ask(l,r)); 35 else if(k==1)scanf("%d",&d),d=o?(d+ans)%(n+1):d,add(l,r,d); 36 else scanf("%d",&d),d=o?(d+ans)%(n+1):d,swap(find(l<<d,l+1<<d),find(r<<d,r+1<<d)),find(l<<d,l+1<<d),find(r<<d,r+1<<d); 37 } 38 }
T3:Match
大意:$[1,2n]$内所有数两两配对,求每对匹配的差的绝对值的方差的期望。$n \le 10^8$
根据数据范围猜测,这题有低于线性的式子。猜测它的次数不高。
答案是分数,小点找规律发现分母都是$n$
小点搜索打表+高斯消元。得到答案式$ans=\frac{10n^2-13n^1-1n^0-86n^{-1}}{45}$
具体含义见题解。还在啃。
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long n,a[7][7]; 4 #define mod 1000000007 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 6 void Gauss(){ 7 for(int i=1;i<=5;++i){ 8 int iv=qp(a[i][i],mod-2);for(int j=i;j<=6;++j)a[i][j]=a[i][j]*1ll*iv%mod; 9 for(int j=1;j<=5;++j)if(i!=j)for(int k=6;k>=i;--k)a[j][k]=(a[j][k]-1ll*a[j][i]*a[i][k]%mod+mod)%mod; 10 } 11 } 12 int main(){ 13 a[1][6]=0,a[2][6]=333333336,a[3][6]=207407410,a[4][6]=800000008,a[5][6]=746666676; 14 for(int i=1;i<=5;++i)a[i][1]=i*i*i,a[i][2]=i*i,a[i][3]=i,a[i][4]=1,a[i][5]=qp(i,mod-2); 15 Gauss(); 16 cin>>n;cout<<(a[1][6]*n%mod*n%mod*n+a[2][6]*n%mod*n%mod+a[3][6]*n+a[4][6]+a[5][6]*qp(n,mod-2))%mod<<endl; 17 }
1 #include<cstdio> 2 #define mod 1000000007 3 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 4 main(){int n;scanf("%d",&n);printf("%lld",(222222224ll*n%mod*n%mod+311111113ll*n+177777779+288888891ll*qp(n,mod-2))%mod);}