bzoj 4818: [Sdoi2017]序列计数
Posted Boss.Pi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4818: [Sdoi2017]序列计数相关的知识,希望对你有一定的参考价值。
Description
Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数。Alice还希望
,这n个数中,至少有一个数是质数。Alice想知道,有多少个序列满足她的要求。
Solution
补集转换
用没有质数限制的方案-一个质数都没有的方案
然后这个题是无序的,这样就非常好做了
设 \(f[i][j]\) 表示选 \(i\) 个数,和 \(\mod p=i\) 的方案数
\(f[i+1][(j+k)\mod P]=f[i][j]*g[k]\)
\(g[k]\) 表示 \(\mod P=k\) 的数的个数
矩阵快速幂优化一下即可
#include<bits/stdc++.h>
using namespace std;
const int N=2e7+10,mod=20170408;
int n,m,P,prime[N],num=0;bool vis[N];
void priwork(){
vis[1]=1;
for(int i=2;i<=m;i++){
if(!vis[i])prime[++num]=i;
for(int j=1;j<=num && i*prime[j]<=m;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
struct mat{
int a[101];
mat(){memset(a,0,sizeof(a));}
void clear(){memset(a,0,sizeof(a));}
mat operator *(const mat &p){
mat ret;
for(int i=0;i<P;i++)
for(int j=0;j<P;j++)
ret.a[(i+j)%P]=(ret.a[(i+j)%P]+1ll*a[i]*p.a[j])%mod;
return ret;
}
};
inline void ksm(mat &S,mat T,int k){
while(k){
if(k&1)S=S*T;
T=T*T;k>>=1;
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m>>P;
priwork();
mat S,T;
S.a[0]=1;
for(int i=1;i<=m;i++)T.a[i%P]++;
ksm(S,T,n);
int ans=S.a[0];
S.clear();T.clear();S.a[0]=1;
for(int i=1;i<=m;i++)if(vis[i])T.a[i%P]++;
ksm(S,T,n);ans=(ans-S.a[0]+mod)%mod;
printf("%d\n",ans);
return 0;
}
以上是关于bzoj 4818: [Sdoi2017]序列计数的主要内容,如果未能解决你的问题,请参考以下文章