[Bzoj4818]序列计数(矩阵乘法+DP)

Description

题目链接

Solution

容斥原理,答案为忽略质数限制的方案数减去不含质数的方案数

然后矩阵乘法优化一下DP即可

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 120
using namespace std;

const int MOD=20170408;
int n,m,p,pri[2000010],cnt[N],top;
bool vis[20000010];

struct info{
	int A[N][N];
	info(){for(int i=0;i<p;++i)for(int j=0;j<p;++j)A[i][j]=0;}
	int *operator [](int x){return A[x];}
	friend info operator *(info a,info b){
		info c;
		for(int i=0;i<p;++i)
			for(int j=0;j<p;++j)
				for(int k=0;k<p;++k)
					c[i][j]=(c[i][j]*1ll+1ll*a[i][k]*b[k][j]%MOD)%MOD;
		return c;
	}
}t1,t2,g;

inline info Pow(info A,int c){
	info res;
	for(int i=0;i<p;++i) res[i][i]=1;
	for(;c;c>>=1,A=A*A) if(c&1) res=res*A;
	return res;
}

int main(){
	scanf("%d%d%d",&n,&m,&p);
	vis[1]=1;
	for (int i=2;i<=m;i++){
		if (!vis[i])pri[++top]=i;
		for (int j=1;j<=top&&i*1ll*pri[j]<=m;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
	for(int i=1;i<=m;++i) cnt[i%p]++;
	for(int i=0;i<p;++i)for(int j=0;j<p;++j)g[i][j]=cnt[(i-j+p)%p];	
	t1[0][0]=t2[0][0]=1;
	t1=t1*Pow(g,n);
	memset(cnt,0,sizeof(cnt));
	for(int i=1;i<=m;++i) if(vis[i]) cnt[i%p]++;
	for(int i=0;i<p;++i)for(int j=0;j<p;++j)g[i][j]=cnt[(i-j+p)%p];	
	t2=t2*Pow(g,n);
	printf("%d
",(t1[0][0]-t2[0][0]+MOD)%MOD);
	return 0;
}
原文地址:https://www.cnblogs.com/void-f/p/8708497.html