LOJ6436 [PKUSC2018] 神仙的游戏 【FFT】

题目分析:

题目要求前后缀相同,把串反过来之后是一个很明显的卷积的形式。这样我们可以完成初步判断(即可以知道哪些必然不行)。

然后考虑一下虽然卷积结果成立,但是存在问号冲突的情况。

箭头之间应当不存在1。不然就和图上所画的一样。注意到它每隔len个跳一次,所以相当于调和级数,利用原有信息判断即可。

字符串转化的方式有很多种。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = (1<<19)+5;
 5 
 6 const int mod = 998244353;
 7 const int gg = 3;
 8 
 9 char str[maxn];
10 
11 int n,m,len,a[maxn<<1],b[maxn<<1],ord[maxn<<1];
12 
13 int f[maxn<<1],iv;
14 
15 int fast_pow(int now,int pw){
16     int ans = 1,dd = now,bit = 1;
17     while(bit <= pw){
18     if(bit & pw) {ans = (1ll*ans*dd)%mod;}
19     dd = (1ll*dd*dd)%mod;
20     bit<<=1;
21     }
22     return ans;
23 }
24 
25 void fft(int *d,int dr){
26     for(register int i=0;i<m;i++) if(i < ord[i]) swap(d[i],d[ord[i]]);
27     for(register int i=1;i<m;i<<=1){
28     int wn = fast_pow(gg,(mod-1)/(2*i));
29     if(dr == -1) wn = fast_pow(wn,mod-2);
30     for(register int j=0;j<m;j+=(i<<1)){
31         for(register int k=0,w=1;k<i;k++,w = (1ll*w*wn)%mod){
32         int x = d[j+k],y = (1ll*w*d[j+k+i])%mod;
33         d[j+k] = x+y; d[j+k] >=mod?d[j+k]-=mod:1;
34         d[j+k+i] = x-y;
35         d[j+k+i] < 0?d[j+k+i]+=mod:1;
36         }
37     }
38     }
39     if(dr == -1){
40     for(register int i=0;i<m;i++) d[i] = (1ll*d[i]*iv)%mod;
41     }
42 }
43 
44 void work(){
45     int n = strlen(str);m = 1;
46     while(m < 2*n){m<<=1;len++;} iv = fast_pow(m,mod-2);
47     for(register int i=0;i<m;i++) ord[i] = (ord[i>>1]>>1)+((i&1)<<len-1);
48 
49     for(register int i=0;i<n;i++) {
50     if(str[i] == '0') a[i] = 1;
51     else if(str[i] == '1') b[n-i-1] = 1;
52     }
53     
54     fft(a,1); fft(b,1); 
55     for(register int i=0;i<m;i++) {
56     f[i] = (1ll*a[i]*b[i])%mod;
57     }
58     
59     memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
60     
61     for(register int i=0;i<n;i++) {
62     if(str[i] == '1') a[i] = 1;
63     else if(str[i] == '0') b[n-i-1] = 1;
64     }
65     
66     fft(a,1); fft(b,1); 
67     for(register int i=0;i<m;i++) {
68     f[i] += (1ll*a[i]*b[i])%mod; if(f[i] >mod)f[i]-=mod;
69     }
70     
71     fft(f,-1);
72 
73     for(register int i=0;i<n-1;i++){
74     int now = n-1-i;
75     for(register int j=i-now;j>=0;j-=now){
76         f[i] |= f[j];
77     }
78     }
79 
80     long long ans = 0;
81     for(register int i=1;i<=n;i++){
82     ans ^= (1ll*(f[i-1]==0)*i*i);
83     }
84     printf("%lld",ans);
85 }
86 
87 int main(){
88     scanf("%s",str);
89     work();
90     return 0;
91 }
原文地址:https://www.cnblogs.com/Menhera/p/9171962.html