Bzoj4818:生成函数 快速幂

转来的题面:

首先这题显然补集转化,就是用全部方案减去不含任何质数的方案。
然后怎么做呢?
考虑m比较小,我们能大力把<=m的质数全都筛出来。
发现n很大,要么倍增要么快速幂......
发现p相当小,所以我们能在mod p的同余系下做啊。

一看到同余系下求方案数立刻想到卷积和生成函数......
假设我们有一个多项式f(x),其中x^i的系数为a个数的序列mod p为i的方案数(a为我们引入的变量)。
同时我们有另一个多项式g(x),其中x^i的系数为b个数的序列mod p为i的方案数(b为我们引入的变量)。
那么,我们如果让f(x)和g(x)做卷积的话,新的多项式x^i的系数就是(a+b)个数的序列mod p为i的方案数的说。
这就是生成函数了。

回到这个题,我们先初始化多项式f(x),令x^i的系数为为1个数mod p为i的方案数。
然后我们求出这个多项式的n次方,就是我们需要的答案了。

发现这道题的p很小,我们连FFT都不用,直接用一个多项式类暴力快速幂就行了。复杂度O(m+p^2logn),跑的飞起。

话说为什么p才100啊,如果修改一下模数然后NTT的话,可以做到p为1e5级别,n为1e18级别的。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define debug cout
 6 typedef long long int lli;
 7 using namespace std;
 8 const int maxn=1e2+1e1,maxl=2e7+1e2,lim=2e7;
 9 const int mod=20170408;
10 
11 bool vis[maxl];
12 int p,m;
13 
14 struct Poly {
15     lli dat[maxn];
16     Poly() {
17         memset(dat,0,sizeof(dat));
18     }
19     lli& operator [] (const int &x) {
20         return dat[x];
21     }
22     const lli& operator [] (const int &x) const {
23         return dat[x];
24     }
25     friend Poly operator * (const Poly &a,const Poly &b) {
26         Poly ret;
27         for(int i=0;i<p;i++) for(int j=0;j<p;j++) {
28             ( ret[(i+j)%p] += a[i] * b[j] % mod ) %= mod;
29         }
30         return ret;
31     }
32 }full,oly;
33 
34 inline void sieve() {
35     static int prime[maxl],cnt;
36     vis[1] = 1;
37     for(int i=2;i<=m;i++) {
38         if( !vis[i] ) prime[++cnt] = i;
39         for(int j=1;j<=cnt&&(lli)i*prime[j]<=m;j++) {
40             vis[i*prime[j]] = 1;
41             if( ! ( i % prime[j] ) ) break;
42         }
43     }
44 }
45 
46 inline void init() {
47     for(int i=1;i<=m;i++) {
48         full[i%p]++;
49         if( vis[i] ) oly[i%p]++;
50     }
51 }
52 
53 inline Poly fastpow(Poly base,int tim) {
54     Poly ret = base; --tim;
55     while( tim ) {
56         if( tim & 1 ) ret = ret * base;
57         if( tim >>= 1 ) base = base * base;
58     }
59     return ret;
60 }
61 
62 int main() {
63     static int n;
64     static lli ans;
65     scanf("%d%d%d",&n,&m,&p) , sieve();
66     init();
67     full = fastpow(full,n) , oly = fastpow(oly,n);
68     ans = ( full[0] - oly[0] + mod ) % mod;
69     printf("%lld\n",ans);
70     return 0;
71 }
View Code

 

posted @ 2018-03-12 16:46  Cmd2001  阅读(238)  评论(0编辑  收藏  举报