[考试反思]0116省选模拟9:赌注
又是运气场。。。
T2有一大堆结论不是很可想。T1暴力分给了20剩下的十分麻烦。T3是个十合一。
什么神奇考试。。。
考场上看了一下前两题觉得不是很可做。
于是直接奔着提答去了,最后只剩下100分钟的时候才回来看前两题。
然后还是觉得T1数上树非常恶心于是式子都没化打暴力跑路,T2打结论啥也想不出来,只考虑了第一种情况扔上继续跑路。
于是又一次跑到了T3。
然而非常弱智,T1的根号筛欧拉函数又写挂了。
第三行i写成x了。弱智
然后T3的第7个点我居然把样例文件交上去了。。。。
而且T3的第5个点还没想到用欧拉函数求逆元
然后第8个点的类原题的做法也忘掉了
后来改题的时候线筛欧拉函数又写错了
过年回家希望有人能送我个好使点的脑子。。。
这场考试也纯粹是运气好,平时提答做的比较多所以占了点便宜。
而且刚题了还赶上没看的题基本不可做。。。
下次要注意。
T1:Surprise me
大意:给定树,求树上所有点对$(u,v)$的$dis(u,v)\varphi(u)\varphi(v)$的期望。$n \le 200000$
还是用到那个结论:$varphi(ab)=\frac{\varphi(a)\varphi(b) gcd(a,b)}{\varphi(gcd(a,b))}$
把$gcd$提出去,反演化式子,得到$\sum\limits_{p=1} f(p) \sum\limits_{i=1}^{\frac{n}{p}} \sum\limits_{j=1}^{\frac{n}{p}} dep_{ip} \varphi(ip) \varphi(jp) +dep_{jp} \varphi(ip) \varphi(jp) -2dep_{lca(ip,jp) \varphi(ip) \varphi(jp)}$
其中$f(p)=\sum\limits_{d|p} \frac{d}{\varphi(d)} \mu(\frac{p}{d})$
对于要求的式子,前两部分可以乘法分配律求和直接处理。最后一个部分考虑树上$dp$
发现一共只涉及到了$n\ ln\ n$个点,每次只对需要的点做复杂度就没什么问题了。于是想到虚树。
虚树这种东西其实不是特别难,大概意思就是把所有要求的点按照$dfn$排序后依次考虑相邻两项的$lca$,用栈维护时分类讨论连边。
这道题的思路其实也不是特别难,但是代码是真的恶心。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 1000000007 4 #define S 400005 5 int n,r[S],dep[S],eu[S],dfn[S],fir[S],l[S],to[S],ec,T,ST[19][S],bin[S],F[S]; 6 int p[S],pc,mu[S],phi[S],np[S],iv[S],sum[S],ans,sta[S],tp,rp[S],sphi[S]; 7 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;} 8 int mo(int a){return a>=mod?a-mod:a;} 9 void dfs(int p,int fa){ 10 dep[p]=dep[fa]+1;eu[++T]=p;dfn[p]=T; 11 for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p),eu[++T]=p; 12 } 13 int lca(int x,int y){ 14 x=dfn[x];y=dfn[y];if(x>y)swap(x,y); 15 int B=bin[y-x+1]; 16 return dep[ST[B][x]]<dep[ST[B][y-(1<<B)+1]]?ST[B][x]:ST[B][y-(1<<B)+1]; 17 } 18 int cmp(int a,int b){return dfn[a]<dfn[b];} 19 void DFS(int p,int rat){ 20 sphi[p]=0; 21 for(int i=fir[p];i;i=l[i])DFS(to[i],rat),sphi[p]=mo(sphi[p]+sphi[to[i]]); 22 rat=1ll*rat*dep[p]%mod; 23 for(int i=fir[p];i;i=l[i]) 24 ans=mo(ans+mod-1ll*rat*sphi[to[i]]%mod*mo(mod+sphi[p]-sphi[to[i]])%mod), 25 ans=mo(ans+mod-2ll*rat%mod*sphi[to[i]]%mod*phi[p]*rp[p]%mod); 26 ans=mo(ans+mod-1ll*rp[p]*phi[p]*phi[p]%mod*rat%mod); 27 sphi[p]=mo(sphi[p]+phi[p]*rp[p]); 28 fir[p]=rp[p]=0; 29 } 30 int main(){ 31 scanf("%d",&n); 32 for(int i=1,x;i<=n;++i)scanf("%d",&x),r[i]=x; 33 for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(r[a],r[b]),link(r[b],r[a]); 34 dfs(1,0); 35 for(int i=1;i<=T;++i)ST[0][i]=eu[i]; 36 for(int i=1;i<=18;++i)for(int j=1<<i;j<1<<i+1&&j<=T;++j)bin[j]=i; 37 for(int i=1;i<=18;++i)for(int j=1;j+(1<<i)-1<=T;++j) 38 ST[i][j]=ST[i-1][dep[ST[i-1][j]]<dep[ST[i-1][j+(1<<i-1)]]?j:j+(1<<i-1)]; 39 mu[1]=phi[1]=iv[1]=1; 40 for(int i=2;i<=n;++i){ 41 if(!np[i])p[++pc]=i,mu[i]=-1,phi[i]=i-1; 42 for(int j=1,x;j<=pc&&(x=i*p[j])<=n;++j) 43 if(i%p[j])np[x]=1,mu[x]=-mu[i],phi[x]=phi[i]*(p[j]-1); 44 else{np[x]=1;phi[x]=phi[i]*p[j];break;} 45 } 46 for(int i=2;i<=n;++i)iv[i]=mod-1ll*mod/i*iv[mod%i]%mod; 47 for(int d=1;d<=n;++d)for(int g=d;g<=n;g+=d) 48 F[g]=(F[g]+1ll*d*iv[phi[d]]*mu[g/d]%mod)%mod,sum[d]=mo(sum[d]+phi[g]); 49 for(int i=1;i<=n;++i)F[i]=mo(F[i]%mod+mod),fir[i]=0; 50 for(int p=1;p<=n;++p){ 51 int d=0,N=n/p,rt;ec=0; 52 for(int i=p;i<=n;i+=p)d=(d+1ll*dep[i]*phi[i])%mod,r[i/p]=i,rp[i]=1; 53 ans=(ans+2ll*d*sum[p]%mod*F[p])%mod; 54 sort(r+1,r+1+N,cmp); 55 rt=r[1];for(int i=2;i<=N;++i)rt=lca(rt,r[i]);tp=0; 56 for(int i=1,l;i<=N;++i){ 57 if(!tp)goto E; 58 l=lca(r[i],sta[tp]); 59 if(l==sta[tp])goto E; 60 while(tp>1&&dfn[l]<=dfn[sta[tp-1]])link(sta[tp-1],sta[tp]),tp--; 61 if(sta[tp]!=l)link(l,sta[tp]),sta[tp]=l; 62 E: sta[++tp]=r[i]; 63 }while(tp>1)link(sta[tp-1],sta[tp]),tp--; 64 DFS(rt,mo(F[p]<<1)); 65 } 66 printf("%lld\n",1ll*ans*iv[n]%mod*iv[n-1]%mod); 67 }
T2:过河(river)
大意:送$n$猪过河,有$m$个三元关系,如果这三个在同一岸就非法。每次运一个可以往回运。问能否过河。$n\le 1000,m\le 3000$
如果所有三元关系的交集为空,一定非法,因为第一遍过去时剩在这一岸的一定会打架。
所以我们提出它们的交集,剩下一些二元组看成边。边上两点不能在同一岸,这些条件是否矛盾就看它是否存在奇环。
否则进行奇偶染色后就是一种合法的分岸方法。
特别的我们要考虑运那只特殊的猪,在它前后运的那两只并不会产生矛盾(因为特殊的猪在船上)
转化问题:给定图,去掉两个点之后是否为二分图。
暴力就是枚举两个点。要注意判断输入数据中三元环有元素相同的情况。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,fir[1001],l[6003],to[6003],a[3111],b[3111],c[3111],P,co[1111],ok,ec; 4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;l[++ec]=fir[b];fir[b]=ec;to[ec]=a;} 5 void dfs(int p,int c){ 6 co[p]=c; 7 for(int i=fir[p];i&&ok;i=l[i])if(!co[to[i]])dfs(to[i],c^1); 8 else if(co[to[i]]==co[p])ok=0; 9 } 10 int main(){//freopen("river1.in","r",stdin); 11 int t;cin>>t;while(t-->0){ 12 cin>>n>>m;P=0; 13 for(int i=1;i<=m;++i){cin>>a[i]>>b[i]>>c[i];if(a[i]==b[i]||b[i]==c[i])i--,m--;} 14 for(int i=1;i<=n;++i){ 15 for(int j=1;j<=m;++j)if(a[j]==i||b[j]==i||c[j]==i);else goto X; 16 P=i;X:; 17 } 18 if(!P){puts("no");continue;} 19 for(int i=1;i<=n;++i)if(i!=P)for(int j=i+1;j<=n;++j)if(j!=P){ 20 for(int k=1;k<=n;++k)co[k]=fir[k]=0;ec=0; 21 for(int k=1;k<=m;++k) 22 if(a[k]==P){if(b[k]!=i&&b[k]!=j&&c[k]!=i&&c[k]!=j)link(b[k],c[k]);} 23 else if(b[k]==P){if(a[k]!=i&&a[k]!=j&&c[k]!=i&&c[k]!=j)link(a[k],c[k]);} 24 else {if(b[k]!=i&&b[k]!=j&&a[k]!=i&&a[k]!=j)link(b[k],a[k]);} 25 ok=1; 26 for(int k=1;k<=n&&ok;++k)if(!co[k])dfs(k,2); 27 if(ok)goto Y; 28 }Y:puts(ok?"yes":"no"); 29 } 30 }
正解是枚举去掉的第一个点,对于其余边建出$dfs$树,看哪些点能够成为被删的第二个点。
这个点需要存在在所有的奇环内。而所有的奇环在$dfs$树上的表现形式只有两种:
1,返祖边+树边。其中返祖边跨越的树上距离为偶数。
2,两条返祖边+树边。其中两条返祖边的树上距离一奇一偶。
对于第一种情况我们打一个差分标记记录就可以。
对于第二种情况,我们在判断点$p$时,要保证$p$的每一个儿子的子树不存在一奇一偶的返祖边。
注意这里所说的第二种情况是对于每一个儿子的子树考虑的,而不是所有儿子加起来。
第二种情况的判断方法我想$xm$学的大神做法,像$tarjan$一样记一个回溯值按照深度判就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,fir[1001],l[6003],to[6003],a[3111],b[3111],c[3111],P,ok,ec; 4 int odd[1111],dep[1111],oddcnt,f[1111],Odd[1111],Even[1111]; 5 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;l[++ec]=fir[b];fir[b]=ec;to[ec]=a;} 6 void dfs(int p,int fa){ 7 dep[p]=dep[fa]+1;f[p]=fa; 8 for(int i=fir[p];i;i=l[i])if(to[i]!=fa) 9 if(!dep[to[i]])dfs(to[i],p),odd[p]+=odd[to[i]],Even[p]=min(Even[p],Even[to[i]]),Odd[p]=min(Odd[p],Odd[to[i]]); 10 else if(dep[p]-dep[to[i]]&1){if(dep[to[i]]<dep[p])Even[p]=min(Even[p],dep[to[i]]);} 11 else if(dep[to[i]]<dep[p])odd[p]++,odd[f[to[i]]]--,oddcnt++,Odd[p]=min(Odd[p],dep[to[i]]); 12 } 13 int main(){//freopen("river1.in","r",stdin); 14 int t;cin>>t;while(t-->0){ 15 cin>>n>>m;P=0; 16 for(int i=1;i<=m;++i)cin>>a[i]>>b[i]>>c[i]; 17 for(int i=1;i<=n;++i){ 18 for(int j=1;j<=m;++j)if(a[j]==i||b[j]==i||c[j]==i);else goto X; 19 P=i;X:; 20 } 21 if(!P){puts("no");continue;} 22 for(int x=1;x<=n;++x){ 23 for(int i=1;i<=n;++i)fir[i]=odd[i]=dep[i]=f[i]=0,Odd[i]=Even[i]=1234567;ec=1;oddcnt=ok=0; 24 for(int i=1;i<=m;++i) 25 if(a[i]==P){if(b[i]!=x&&c[i]!=x)link(b[i],c[i]);} 26 else if(b[i]==P){if(a[i]!=x&&c[i]!=x)link(a[i],c[i]);} 27 else if(c[i]==P){if(a[i]!=x&&b[i]!=x)link(a[i],b[i]);} 28 for(int i=1;i<=n;++i)if(i!=x&&i!=P&&!dep[i])dfs(i,0); 29 for(int i=1;i<=n;++i)if(odd[i]==oddcnt){ 30 int r=1; 31 for(int j=fir[i];j;j=l[j])if(dep[to[j]]>dep[i]&&Even[to[j]]<dep[i]&&Odd[to[j]]<dep[i])r=0; 32 ok|=r; 33 }if(ok)break; 34 }puts(ok?"yes":"no"); 35 } 36 }
T3:NPIO十合一
大意:无题面。给出$10$份超慢$std$与数据生成/输出生成代码,求解答案。
National Programming Informatic Olympic???
若答案数组为$c$。输出生成方式$x=(233\times x \ xor \ c[i])mod \ 1000000007$
$Test1:$读入数组$a,b$对位求和后输出。数组大小$10^9$
模拟题意生成数据并输出即可。预计耗时$18s$。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 freopen("npio1.out","w",stdout); 5 const int n=1000000000;register int x=233,y=233,res=0; 6 for(int i=1;i<=n;++i)x=(37*x+666)%19260817; 7 for(int i=1;i<=n;++i) 8 x=(37*x+666)%19260817, 9 y=(37*y+666)%19260817, 10 res=(233LL*res^x%10000+y%10000)%1000000007; 11 cout<<res<<endl; 12 }
$Test2:$读入数组$a,b$卷积后输出。数组大小$5000000$。值域$2^{15}$。常系数线性齐次递推生成。
可以$MTT/FFT?$我用的$Test3$的方法。预计耗时$2s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int bit=1<<15; 4 int A[bit],B[bit],C[bit<<1]; 5 int main(){ 6 freopen("npio2.out","w",stdout); 7 const int n=5000000;register int x=23333; 8 for(int i=0;i<bit;++i)A[i]=x=(233*x+37)&32767; 9 for(int i=bit;i<n;++i)x=(233*x+37)&32767; 10 for(int i=0;i<bit;++i)B[i]=x=(233*x+37)&32767; 11 for(int i=0;i<bit;++i)for(int j=0;j<bit;++j)C[i+j]=(C[i+j]+A[i]*B[j])%998244353; 12 register int ans=0; 13 for(int i=0;i<n;++i){ 14 register int bl=i>>15,lw=i&32767,tmp=(C[lw]*(bl+1ll)+1ll*bl*C[lw|bit])%998244353; 15 if(i%1000000==0)cerr<<i<<endl; 16 ans=(ans*233LL^tmp)%1000000007; 17 }cout<<ans<<endl; 18 }
$Test3:$读入数组$a,b$卷积后输出。数组大小$10^9$。值域$2^{15}$。常系数线性齐次递推生成。
根据生成方式发现有循环节,打出来发现循环节恰好为$2^{15}$。于是直接做$2^{16}$的卷积就行了。
然后乘上错位的系数即可。预计耗时$28s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int bit=1<<15; 4 int A[bit],B[bit],C[bit<<1]; 5 int main(){ 6 freopen("npio3.out","w",stdout); 7 const int n=1000000000;register int x=23333; 8 for(int i=0;i<bit;++i)A[i]=x=(233*x+37)&32767; 9 for(int i=bit;i<n;++i)x=(233*x+37)&32767; 10 for(int i=0;i<bit;++i)B[i]=x=(233*x+37)&32767; 11 for(int i=0;i<bit;++i)for(int j=0;j<bit;++j)C[i+j]=(C[i+j]+A[i]*B[j])%998244353; 12 register int ans=0; 13 for(int i=0;i<n;++i){ 14 register int bl=i>>15,lw=i&32767,tmp=(C[lw]*(bl+1ll)+1ll*bl*C[lw|bit])%998244353; 15 if(i%1000000==0)cerr<<i<<endl; 16 ans=(ans*233LL^tmp)%1000000007; 17 }cout<<ans<<endl; 18 }
$Test4:$排序$a$数组。数组大小与值域是$10^9$。
发现循环节很长。。。开$short$直接桶排,重复的数不多。预计耗时$45s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 short M[1000000001]; 4 int main(){ 5 freopen("npio4.out","w",stdout); 6 unsigned int x=23333; 7 for(int i=1;i<=1000000000;++i){ 8 x=x^(x<<13); 9 x=x^(x>>17); 10 x=x^(x<<5); 11 M[x%1000000000]++; 12 if(i%100000==0)cerr<<i<<endl; 13 }int ans=0; 14 for(int i=0;i<1000000000;++i)while(M[i]) 15 M[i]--,ans=(233LL*ans^i)%1000000007; 16 cout<<ans<<endl; 17 }
$Test5:$随机树。按序输出子树大小。数组大小$10^9$。常系数线性齐次递推生成。模数$233$进制数$2^{32}$
考场上没想出来。
应该算是最难的一个。可以发现模数与进制数互质,存在逆元$233^{2^{31}-1}$。
所以可以倒推回来存子树大小。大小数组对于较小的位置开$int$较大位置开$short$。$int$开得越多越好。
预计耗时$43s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 short d[1000000001];int D[270000001]; 4 inline int addd(register const int&p,register const int&w){ 5 if(p<=270000000)D[p]+=w; 6 else d[p]+=w; 7 } 8 inline int deg(register const int&p){ 9 if(p<=270000000)return D[p]; 10 else return (int)d[p]; 11 } 12 int main(){ 13 freopen("npio5.out","w",stdout); 14 const int n=1000000000;register unsigned int x=23333,iv=233,Iv=1;register int ans=0; 15 for(int i=0;i<31;++i)Iv*=iv,iv*=iv;iv=Iv; 16 for(int i=1;i<n;++i)x=233*x+37; 17 for(int i=1;i<=n;++i)addd(i,1); 18 for(int i=n-1;i;--i){ 19 int fa=x%i+1;addd(fa,deg(i+1)); 20 x-=37;x*=iv; 21 if(i%1000000==0)cerr<<i<<endl; 22 } 23 for(int i=1;i<=n;++i)ans=(233LL*ans^deg(i))%1000000007; 24 cout<<deg(1)<<' '<<ans<<endl; 25 }
$Test6:$随机基环树。随机树加一条边求最小生成树。数据范围$10^9$。值域$2^{15}$
最机智的做法取模$Dyyb$。因为值域只有$2^{15}$所以依次尝试去掉这个边权的边,和样例拍上就行。
我的弱智做法是因为随机树期望深度为$ln$级别,所以爆跳父亲求$lca$,找环上最小边。预计耗时$6s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int n=1000000000; 4 int fx[11111],tfx[11111],fy[11111],tfy[11111],cfx,cfy,ans,r[4],tans; 5 int main(){ 6 freopen("npio6.out","w",stdout); 7 unsigned int x=23333,w=233,a,b; 8 for(int i=1;i<n;++i)x=233*x+37,w=23*w+37&32767; 9 x=a=233*x+37;b=233*x+37;ans=23*w+37&32767; 10 fx[0]=a=a%n+1,fy[0]=b=b%n+1; 11 //cout<<a<<' '<<b<<endl; 12 while(a!=1){ 13 x=23333;w=233;cfx++; 14 for(int i=1;i<a;++i)x=233*x+37,w=(23*w+37)&32767; 15 a=fx[cfx]=x%(a-1)+1;tfx[cfx]=w;//cerr<<a<<endl; 16 }//cout<<cfx<<endl; 17 while(b!=1){ 18 x=23333;w=233;cfy++; 19 for(int i=1;i<b;++i)x=233*x+37,w=(23*w+37)&32767; 20 b=fy[cfy]=x%(b-1)+1;tfy[cfy]=w; 21 }//cout<<cfy<<endl; 22 for(int i=0;i<=cfx;++i)for(int j=0;j<=cfy;++j)if(fx[i]==fy[j]){ 23 for(int k=1;k<=i;++k)ans=max(ans,tfx[k]); 24 for(int k=1;k<=j;++k)ans=max(ans,tfy[k]); 25 goto O; 26 }O: 27 w=233; 28 long long nans=-ans; 29 for(int i=1;i<=n;++i)w=23*w+37&32767,nans+=w; 30 for(int i=0;i<4;++i)r[i]=nans%10000,nans/=10000; 31 for(int i=0;i<4;++i)tans=(tans*233LL^r[i])%1000000007; 32 cout<<tans<<endl; 33 }
$Test7:$维护堆支持插入/弹顶。每次操作后堆顶为答案。操作数及值域$10^9$。操作是随机的。
因为期望下弹与加次数相同,所以直接暴力模拟。元素个数始终没有超过$30000$所以不太慢。
预计耗时$1min$
1 #include<bits/stdc++.h> 2 using namespace std; 3 priority_queue<int>Q; 4 const int n=1000000000,mod=1000000009; 5 int main(){ 6 freopen("npio7.out","w",stdout); 7 int sz=0,y=23333,ans=0;unsigned int x=233; 8 for(int i=1;i<=n;++i){ 9 x=(x*23+777)%19260817; 10 if(sz<2||(!(x&1)))y=y*233+567,Q.push(y),++sz; 11 else Q.pop(),sz--; 12 if(i%10000000==0)cerr<<i<<' '<<sz<<endl; 13 ans=(233LL*ans^(Q.top()%mod+mod)%mod)%1000000007; 14 }cout<<ans<<endl; 15 }
$Test8:$动态加入数,每次加入后中位数为答案。操作数及值域$10^9$。数据随机。
考场上没想出来。
类似于原题。以前有一个是$2\times 10^9$之内所有质数乘什么东西来着。
循环节还是很长,开$short$桶维护每个数出现次数,维护一个指针表示当前值与这个值的排名。
在随机数据下指针的移动次数很少。刚开始跑的慢后来密集之后很快。
预计耗时$70s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 short v[1000000000]; 4 int main(){freopen("npio8.out","w",stdout); 5 const int n=1000000000;register unsigned int x=23333; 6 register int p=0,rk=0,ans=0; 7 for(int i=1;i<=n;++i){ 8 x=233*x+37; 9 v[x%1000000000]++; 10 if(x%1000000000<p)rk++; 11 while(rk+v[p]<i+1>>1)rk+=v[p],p++; 12 while(rk+1>i+1>>1)p--,rk-=v[p]; 13 ans=(233LL*ans^p)%1000000007; 14 if(i%10000000==0)cerr<<i<<endl; 15 } 16 cout<<ans<<endl; 17 }
$Test9:$动态加入数,每次加入后有多少种数即为答案。操作数及值域$10^9$。
$bitset$直接搞就可以。编译预计耗时$70s$。运行预计耗时$50s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 bitset<1000000000>B; 4 const int n=1000000000,mx=1000000000; 5 int main(){ 6 freopen("npio9.out","w",stdout); 7 register unsigned int x=23333,ans=0,r=0; 8 for(int i=1;i<=n;++i){ 9 x=233*x+37; 10 if(!B[x%mx])ans++; 11 B[x%mx]=1; 12 if(i%10000000==0)cerr<<i<<' '<<ans<<endl; 13 r=(233LL*r^ans)%1000000007; 14 }cout<<r<<endl; 15 }
$Test10:$求各个点双中点的编号和,排序后依次输出。点数$10^7$。边数$10^9$。边随机。
生成方式为$x=x \times 233 +37,y=y \times 23+37$。$unsigned \ int$自然溢出。$x,y$初值为$23333,777$
考场上没想出来。
可以发现$x,y$的奇偶性时刻相同。所以奇点之间联通,偶点之间联通。
因为点少边多,所以在随机数据下每个联通块都是点双。
所以所有奇点在一个点双里,所有偶点在一个点双里。直接比较输出即可。
预计耗时$0s$
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 freopen("npio10.out","w",stdout); 5 register int x=5000001*5000000ll%998244353,y=5000000*5000000ll%998244353; 6 cout<<(233ll*y^x)%1000000007<<endl; 7 }
.