Alice 想要得到一个长度为 n 的序列,序列中的数都是不超过 m 的正整数,而且这 n 个数的和是 p 的倍数。
Alice 还希望,这 n 个数中,至少有一个数是质数。
Alice 想知道,有多少个序列满足她的要求。
1≤n≤109,1≤m≤2×107,1≤p≤100
分析
这题做得很爽…
首先是一个套路,维护倍数可以转为维护当前和的模。因此如果递推的话,只需要100个状态,看起来是可做的。但是这个n的范围实在是有点,先列一下再说。
把2e7个数字全部模完,它们对答案的贡献只和剩余类有关。这样我们就能知道在和的模为a时有多少种方案能够凑到b了。得出递推方程
f(i,j)=0≤k<p∑f(i−1,(j−k)mod3)c(k)
其中c(k)是模为k的数有多少个。
至少有一个质数的条件转为无质数,从所有的c中扣去质数后再算一遍方案数,二者相减。
最后,关于n,这个公式能够用快速幂加速。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| #include <cstdio> #include <algorithm> #include <string> #include <vector> #include <cstring> #include <iostream> #include <queue> #include <set> #include <cmath> #include <map> using namespace std; using pii=pair<int,int>; using ll=long long; const int MAXN=110; const int MAXM=20000010; const int MOD=20170408;
bool isnp[MAXM]; vector<int> primes;
void init(int n){ isnp[1]=1; for(int i=2;i<=n;i++){ if(!isnp[i]){ primes.push_back(i); } for(int j=0;j<primes.size() && i*primes[j]<=n;j++){ isnp[i*primes[j]]=1; if(i%primes[j]==0){ break; } } } }
struct Mat{ ll a[MAXN][MAXN];
Mat(){ memset(a,0,sizeof(a)); }
Mat operator*(const Mat &other){ Mat res; for(int i=1;i<MAXN;i++){ for(int j=1;j<MAXN;j++){ for(int k=1;k<MAXN;k++){ res.a[i][j]=(res.a[i][j]+a[i][k]*other.a[k][j]%MOD)%MOD; } } } return res; }
void debug(){ for(int i=1;i<MAXN;i++){ for(int j=1;j<MAXN;j++){ cout<<a[i][j]<<" "; } cout<<endl; } }
void normalize(){ for(int i=1;i<MAXN;i++) { a[i][i] = 1; } } };
Mat qpow(Mat a,int b){ Mat res; res.normalize();
for(;b;b>>=1,a=a*a){ if(b&1)res=res*a; }
return res; } Mat base; int pool[MAXN],nopool[MAXN]; Mat incprime,noprime; int main() { ios::sync_with_stdio(false);
int n,m,p;cin>>n>>m>>p; for(int i=1;i<=m;i++){ pool[i%p]++; nopool[i%p]++; } init(m); for(auto it:primes){ nopool[it%p]--; }
for(int j=1;j<=p;j++){ for(int i=1;i<=p;i++){ incprime.a[i][j]=pool[((j-1-(i-1))%p+p)%p]; noprime.a[i][j]=nopool[((j-1-(i-1))%p+p)%p]; } }
base.a[1][1]=1;
incprime=base*qpow(incprime,n);
noprime=base*qpow(noprime,n);
cout<<((incprime.a[1][1]-noprime.a[1][1])%MOD+MOD)%MOD<<endl;
return 0; }
|