bzoj 3992: [SDOI2015]序列统计
膝盖++,IQ--
SD总是酱紫。。。。。吐槽+++++++
这个乘积的形式是可以用他的原根表示成加法的!!神奇啊!!!
然后加法就很棒棒了,我们可以用生成函数这个东西来计算一下了。
然后NTT就好了!!
还有这里有一个像快速幂的东西,而且把大于模数的东西搞小,是循环卷积的形式吗??好神奇啊
原根真的是劲啊
1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #define LL long long 5 #define pi acos(-1) 6 using namespace std; 7 8 const int mod=(479<<21)+1,G=3,maxn=17000; 9 10 int n,k,sum,m,inv_G,inv_N,T[maxn],vis[maxn],ind,N,rev[maxn],pos[maxn],root; 11 12 int ksm(int x, int p) 13 { 14 int sum=1; 15 for (;p;p>>=1,x=(LL)x*x%mod) 16 if (p&1) sum=(LL)sum*x%mod; 17 return sum; 18 } 19 20 int rever(int x) {int res=0,len=N; while (len--) res<<=1,res^=(x&1),x>>=1; return res;} 21 22 bool check(int x) 23 { 24 int now=1; ++ind; 25 for (int i=1; i<n; i++,now=now*x%n){ 26 if (vis[now]==ind) return 0; 27 vis[now]=ind; 28 } 29 return 1; 30 } 31 int find_root() {for (int i=2; i<=n; i++) if (check(i)) return i;} 32 33 struct Orz 34 { 35 int a[maxn]; 36 void NTT(int opt) 37 { 38 for (int i=0; i<N; i++) if (rev[i]>i) swap(a[rev[i]],a[i]); 39 int g=opt==1?G:inv_G; 40 for (int h=2; h<=N; h<<=1) 41 { 42 int t=ksm(g,(mod-1)/h); 43 for (int i=0; i<N; i+=h) 44 for (int j=0,w=1; j<(h>>1); j++,w=(LL)w*t%mod) 45 { 46 int x=a[i+j],y=(LL)a[i+j+(h>>1)]*w%mod; 47 a[i+j]=(x+y)%mod; a[i+j+(h>>1)]=(x-y+mod)%mod; 48 } 49 } 50 if (opt==-1) for (int i=0; i<N; i++) a[i]=(LL)a[i]*inv_N%mod; 51 } 52 }a,b; 53 54 void quick_pow() 55 { 56 b.a[0]=1; 57 for (;k;k>>=1) 58 { 59 a.NTT(1); 60 if (k&1) 61 { 62 b.NTT(1); for (int i=0; i<N; i++) b.a[i]=(LL)b.a[i]*a.a[i]%mod; 63 b.NTT(-1); for (int i=N-1; i>=n-1; i--) b.a[i-n+1]=(b.a[i-n+1]+b.a[i])%mod,b.a[i]=0; //循环卷积???? 64 } 65 for (int i=0; i<N; i++) a.a[i]=(LL)a.a[i]*a.a[i]%mod; a.NTT(-1); 66 for (int i=N-1; i>=n-1; i--) a.a[i-n+1]=(a.a[i-n+1]+a.a[i])%mod,a.a[i]=0; 67 } 68 } 69 70 int main(int argc, char const *argv[]) 71 { 72 inv_G=ksm(G,mod-2); 73 scanf("%d%d%d%d",&k,&n,&sum,&m); 74 for (int i=1; i<=m; i++) scanf("%d",&T[i]); 75 N=(int)ceil(log2(n))+1; 76 for (int i=0; i<(1<<N); i++) rev[i]=rever(i); 77 N=1<<N; inv_N=ksm(N,mod-2); root=find_root(); 78 for (int i=0,res=1; i<n-1; i++) pos[res]=i,res=res*root%n; 79 80 for (int i=1; i<=m; i++) if (T[i]) a.a[pos[T[i]]]++; 81 quick_pow(); 82 printf("%d\n",b.a[pos[sum]]); 83 return 0; 84 }