Luogu1357 花园

https://www.luogu.com.cn/problem/P1357

矩阵快速幂优化\(DP\)

\(n\)的范围很大,考虑矩阵快速幂优化

我们首先要建立一个矩阵(根据转移关系构建就好了)

由于是一个环,我枚举了最后\(m\)位,然后把前\(m\)位的答案预处理出来,矩阵快速幂\(n-m\)轮后取我枚举的最后\(m\)位的\(dp\)

实际上,可以只枚举前\(m\)位,直接跑\(n\)轮矩阵快速幂,保证首尾一致就好了(一定是我太菜了QAQ

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 55
#define p 1000000007
#define ll long long
#define bc __builtin_popcount
using namespace std;
ll Rans,n,tot,dp[N],q[N],ans[N][N],trans[N][N],c[N][N];
int m,lim;
void ksm(ll y)
{
	for (int i=0;i<=tot;i++)
		for (int j=0;j<=tot;j++)
			ans[i][j]=0;
	for (int i=0;i<=tot;i++)
		ans[i][i]=1;
	while (y)
	{
		if (y & 1)
		{
			for (int i=0;i<=tot;i++)
				for (int j=0;j<=tot;j++)
					c[i][j]=0;
			for (int k=0;k<=tot;k++)
				for (int i=0;i<=tot;i++)
					for (int j=0;j<=tot;j++)
						c[i][j]=(c[i][j]+ans[i][k]*trans[k][j])%p;
			for (int i=0;i<=tot;i++)
				for (int j=0;j<=tot;j++)
					ans[i][j]=c[i][j];
		}
		for (int i=0;i<=tot;i++)
			for (int j=0;j<=tot;j++)
				c[i][j]=0;
		for (int k=0;k<=tot;k++)
			for (int i=0;i<=tot;i++)
				for (int j=0;j<=tot;j++)
					c[i][j]=(c[i][j]+trans[i][k]*trans[k][j])%p;
		for (int i=0;i<=tot;i++)
			for (int j=0;j<=tot;j++)
				trans[i][j]=c[i][j];
		y >>=1;
	}
}
int main()
{
	scanf("%lld%d%d",&n,&m,&lim);
	tot=(1 << m)-1;
	for (int i=0;i<=tot;i++)
	{
		for (int j=0;j<=tot;j++)
		{
			dp[j]=1;
			if (bc(j)>lim)
			{
				dp[j]=0;
				continue;
			}
			for (int k=1;k<=m;k++)
				if (bc(i & ((1 << k)-1))+bc(j >> k)>lim)
				{
					dp[j]=0;
					break;
				}
		}
		for (int j=0;j<=tot;j++)
			for (int k=0;k<=tot;k++)
				trans[j][k]=0;
		for (int j=0;j<=tot;j++)
			if (bc(j)>lim)
				continue; else
				{
					int nxt=(j << 1) & tot;
					if (bc(nxt)<=lim)
						trans[nxt][j]=1; else
						trans[nxt][j]=0;
					nxt=((j << 1) | 1) & tot;
					if (bc(nxt)<=lim)
						trans[nxt][j]=1; else
						trans[nxt][j]=0;
				}
		ksm(n-m);
		for (int s=0;s<=tot;s++)
			q[s]=0;
		for (int k=0;k<=tot;k++)
			for (int s=0;s<=tot;s++)
				q[s]=(q[s]+ans[s][k]*dp[k])%p;
		Rans=(Rans+q[i])%p;
	}
	Rans=(Rans%p+p)%p;
	printf("%lld\n",Rans);
	return 0;
}
posted @ 2020-08-16 18:15  GK0328  阅读(56)  评论(0编辑  收藏  举报