[HNOI2008]Cards

题目

洛谷
BZOJ

做法

一种置换各个循环里的颜色相同,这个手玩就懂了(唯一性)

三维背包就能做,最后再加个不变的一种置换

My complete code

#include<bits/stdc++.h>
using namespace std;
typedef int LL;
LL const maxn=30;
LL r,b,g,m,p,n,ans;
LL dp[maxn][maxn][maxn],len[maxn*3],a[maxn*3];
bool visit[maxn*3];
inline LL Pow(LL base,LL b){
	LL ret(1);
	while(b){
		if(b&1) ret=ret*base%p;
	    base=base*base%p,b>>=1;
	}return  ret;
}

inline LL Dp(){
	LL cnt(0);
	memset(visit,false,sizeof(visit));
	memset(len,0,sizeof(len));
	memset(dp,0,sizeof(dp));
	for(LL i=1;i<=n;++i){
		if(!visit[i]){
			++cnt;
			for(LL j=i;!visit[j];j=a[j]) 
			    visit[j]=true,++len[cnt];
		}
	}
	dp[0][0][0]=1;
	for(LL i=1;i<=cnt;++i)
		for(LL R=r;R>=0;--R)
		    for(LL B=b;B>=0;--B)
		        for(LL G=g;G>=0;--G){
		        	if(R>=len[i]) dp[R][B][G]=(dp[R][B][G]+dp[R-len[i]][B][G])%p;
		        	if(B>=len[i]) dp[R][B][G]=(dp[R][B][G]+dp[R][B-len[i]][G])%p;
		        	if(G>=len[i]) dp[R][B][G]=(dp[R][B][G]+dp[R][B][G-len[i]])%p;
				}
	return dp[r][b][g];
}
int main(){
	scanf("%d%d%d%d%d",&r,&b,&g,&m,&p);
	n=r+b+g;
	for(LL i=1;i<=m;++i){
		for(LL j=1;j<=n;++j) scanf("%d",a+j);
		ans=(ans+Dp())%p;
	}
	for(LL i=1;i<=n;++i) a[i]=i;
	ans=(ans+Dp())%p;
	printf("%d",ans*Pow(m+1,p-2)%p);
	return 0;
}
posted @ 2019-02-12 16:42  y2823774827y  阅读(209)  评论(0编辑  收藏  举报