LOJ6436 神仙的游戏

mac2022-06-30  158

目录

LOJ6436 神仙的游戏题意题解Code:

LOJ6436 神仙的游戏

题目传送门

题意

\(D\) 和小 \(H\) 是两位神仙。他们经常在一起玩神仙才会玩的一些游戏,比如 “口算一个 4 位数是不是完全平方数” 。

今天他们发现了一种新的游戏:首先称 \(s\) 长度为 \(len\) 的前缀成为\(border\)当且仅当 \(s[1\dots len ] = s[|s|-len + 1\dots |s|]\)。给出一个由01?组成的字符串 \(s\), 将\(s\)中的问号用变成01替换,对每个\(len\)口算是否存在替换问号的方案使得\(s\)长度为\(len\)的前缀成为\(border\),把这个结果记做 \(f(len)\in \{0,1\}\)\(f(len) = 1\) 如果 \(s\) 长度为\(len\)的前缀能够成为 \(border\),否则\(f(len) = 0\)

由于小 \(D\) 和小 \(H\) 是神仙,所以他们计算的\(s\)的长度很长,因此把计算的结果一一比对会花费很长的时间。为了方便比对,他们规定了一个校验值:\((f(1)\times 1^2)~xor~(f(2)\times 2^2)~xor~(f(3)\times 3^2)~xor~\dots~xor~(f(n)\times n^2)\)来校验他们的答案是否相同。xor表示按位异或。但是不巧,在某一次游戏中,他们口算出的校验值并不一样,他们希望你帮助他们来计算一个正确的校验值。当然,他们不强迫你口算,可以编程解决。\((1 \leq |s| \leq 5 * 10 ^ 5)\)

题解

简单的观察可知如果一种长度的border是可行的当且仅当这个字符串中循环节长度为\(n-len\)的字符串是相同的(问号可匹配仍以一个字符),于是我们就有了一种朴素的方法就是枚举border的长度然后\(O(n)\)进行判断。考虑优化这个算法,我们可以记数组\(a\)表示字符串\(s\)中1出现的位置,然后记数组\(b\)表示字符串中0的位置。如果我们将b数组reverse一下,就可以发现如果将这两个数组相乘,那么乘除来的数组内,如果某一位是1,那么说明字符串\(s\)中存在\(i\)\(j\)的字符是不同的,这样我们就可以求出他们的最大循环节len。还有一个就是如果某一个循环节len是不可行,那么循环节\(len'\)满足\(len'|len\)则也是不可行的,这样就可以在\(O(nlog(n))\)的时间内求解。

Code:

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int Md=998244353; const int N=5e5+500; char s[N]; int vis[N]; vector<int>a,b; namespace NTT { inline int Mul(const int &x,const int &y) {return (ll)x*y%Md;} inline int Add(const int &x,const int &y) {return (x+y)>=Md?(x+y-Md):(x+y);} inline int Sub(const int &x,const int &y) {return (x-y)<0?(x-y+Md):(x-y);} int rev[N<<2|1]; int Powe(int x,int y) { int ans=1; while(y) { if(y&1) ans=Mul(ans,x); x=Mul(x,x); y>>=1; } return ans; } void DFT(vector<int>&a,int len) { for(int i=0;i<len;i++) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int i=1;i<len;i<<=1) { int wn=Powe(3,(Md-1)/(i<<1)); for(int j=0;j<len;j+=i<<1) { int nw=1,x,y; for(int k=0;k<i;k++,nw=Mul(nw,wn)) { x=a[j+k],y=Mul(a[i+j+k],nw); a[j+k]=Add(x,y);a[i+j+k]=Sub(x,y); } } } } void IDFT(vector<int>&a,int len) { reverse(a.begin()+1,a.end()); DFT(a,len); int Inv=Powe(len,Md-2); for(int i=0;i<len;i++) a[i]=Mul(a[i],Inv); } vector<int> MUL(vector<int>a,vector<int>b) { int len,n=a.size(),m=b.size(); for(len=1;len<n+m-2;len<<=1); a.resize(len),b.resize(len); for(int i=0;i<len;i++) { rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0); } DFT(a,len);DFT(b,len); for(int i=0;i<len;i++) a[i]=Mul(a[i],b[i]); IDFT(a,len); return a; } } int main() { scanf("%s",s); int n=strlen(s); a.resize(n),b.resize(n+1); for(int i=0;i<n;i++) { if(s[i]=='0') a[i]=1; if(s[i]=='1') b[i]=1; } reverse(b.begin(),b.end()); a=NTT::MUL(a,b); ll ret=(ll)n*n; for(int i=1;i<n;i++) { int f=1; int t=n-i; for(int j=t;j<n;j+=t) { if(a[n-j]||a[n+j]) f=0; } if(f) ret^=(ll)i*i; } printf("%lld\n",ret); return 0; }

转载于:https://www.cnblogs.com/Apocrypha/p/10153596.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)