LOJ #10172. 「一本通 5.4 练习 1」涂抹果酱

爆搜出三进制的状态,因为m<=5,所以状态最多为3*(2^5)=48个,然后就可以用一个二维dp来统计答案了。
可以发现给出行上和给出行下的方案数是一样的,设给出行上的方案数为ans1,给出行下的方案数为ans2,答案即为 ans1*ans2。
所以严格意义上不算是状压dp吧,没有用到二进制状压的精髓。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e4+5,M=50,MOD=1e6;
int n,m,k,cnt,ans1,ans2,ans,id;
int a[M],f[N][M];
bool pd[M][M];
struct number{int a[M];}num[M];

void dfs(int x,int last)
{
	if (x==m+1)
	{
		cnt++;
		for (register int i=1; i<=m; ++i) num[cnt].a[i]=a[i];
		return;
	}
	for (register int i=1; i<=3; ++i)
	if (i!=last)
	{
		a[x]=i;
		dfs(x+1,i);
	}
}

signed main(){
	scanf("%lld%lld",&n,&m);
	dfs(1,-1);
	scanf("%lld",&k);
	for (register int i=1; i<=m; ++i) scanf("%lld",&a[i]);
	for (register int i=1; i<m; ++i) if (a[i]==a[i+1]) {printf("%lld\n",0ll); return 0;}
	
	for (register int i=1; i<cnt; ++i)
	for (register int j=i+1; j<=cnt; ++j) 
	{
		bool jay=true;
		for (register int k=1; k<=m; ++k) if (num[i].a[k]==num[j].a[k]) {jay=false; break;}
		pd[i][j]=pd[j][i]=jay;
	}
	
	for (register int i=1; i<=cnt; ++i) 
	{
		bool jay=true;
		for (register int j=1; j<=m; ++j) if (a[j]!=num[i].a[j]) {jay=false; break;}
		if (jay) {id=i; break;}
	}
	
	f[k][id]=1;
	
	for (register int i=1; i<=cnt; ++i) if (pd[i][id]) f[k+1][i]=1;
	for (register int i=k+2; i<=n; ++i)
	for (register int j=1; j<=cnt; ++j)
	for (register int k=1; k<=cnt; ++k) if (pd[j][k]) f[i][j]=(f[i][j]+f[i-1][k])%MOD;
	
	for (register int i=1; i<=cnt; ++i) if (pd[i][id]) f[k-1][i]=1;
	for (register int i=k-2; i>=1; --i)
	for (register int j=1; j<=cnt; ++j)
	for (register int k=1; k<=cnt; ++k) if (pd[j][k]) f[i][j]=(f[i][j]+f[i+1][k])%MOD;
	
	for (register int i=1; i<=cnt; ++i) ans1=(ans1+f[1][i])%MOD;
	for (register int i=1; i<=cnt; ++i) ans2=(ans2+f[n][i])%MOD;
	ans=(ans1*ans2)%MOD;
	printf("%lld\n",ans);
return 0;
}
发布了64 篇原创文章 · 获赞 29 · 访问量 684

猜你喜欢

转载自blog.csdn.net/Dove_xyh/article/details/103810349
今日推荐