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 }

 

posted @ 2017-04-20 09:48  ws_ccd  阅读(196)  评论(0编辑  收藏  举报