您的位置:首页 > 其它

BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

2016-10-19 09:54 295 查看
时空隧道

和hihocoder的扑克牌那道题是一样的…然后区别就是扑克牌面值相同花色不同也不同,但是颜色不一样…相同就相同了…

懒得再写一遍了…所以直接放扑克牌的题解了…(代码还是bzoj的code)

题目大意:

一副不含王的扑克牌由52张牌组成,由红桃、黑桃、梅花、方块4组牌组成,每组13张不同的面值。现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数。

分析:

其实定义状态有一种很直观的想法,每个人最初的想法—f[a][b][c][d][e][f][g]……[p]

前13维,第k维代表面值为k的牌还剩几张,p代表序列最后一张的面值,也就是当前不能选面值为p的牌,但是这样代码量很大,所以找一种优化方法

F[i][j][k][l][p]代表剩余1张牌的面值种类为i,jkl同理,p代表上一次最后一张牌是属于剩余几张的

至于怎么想到的我至今很困惑…感觉好机智的方法…大概是或许我们并不需要知道每个面值剩余几张牌,因为面值不同剩余牌数相同的牌对答案的转移贡献是相同的,所以只需要记录剩余几张的面值种类就好了

然后就转移就好了

代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxm=16,MOD=1000000007;
int k,c[maxm],num[6];
long long f[maxm][maxm][maxm][maxm][maxm][6];
inline long long dp(int a,int b,int c,int d,int e,int s){
if(f[a][b][c][d][e][s]!=-1)
return f[a][b][c][d][e][s];
if(a==0&&b==0&&c==0&&d==0&&e==0)
return f[a][b][c][d][e][s]=1;
f[a][b][c][d][e][s]=0;
if(a>0)
f[a][b][c][d][e][s]=(f[a][b][c][d][e][s]+dp(a-1,b,c,d,e,0)*(a-(s==1))%MOD)%MOD;
if(b>0)
f[a][b][c][d][e][s]=(f[a][b][c][d][e][s]+dp(a+1,b-1,c,d,e,1)*(b-(s==2))%MOD)%MOD;
if(c>0)
f[a][b][c][d][e][s]=(f[a][b][c][d][e][s]+dp(a,b+1,c-1,d,e,2)*(c-(s==3))%MOD)%MOD;
if(d>0)
f[a][b][c][d][e][s]=(f[a][b][c][d][e][s]+dp(a,b,c+1,d-1,e,3)*(d-(s==4))%MOD)%MOD;
if(e>0)
f[a][b][c][d][e][s]=(f[a][b][c][d][e][s]+dp(a,b,c,d+1,e-1,4)*(e-(s==5))%MOD)%MOD;
return f[a][b][c][d][e][s];
}
signed main(void){
scanf("%d",&k);
memset(num,0,sizeof(num));
for(int i=1;i<=k;i++)
scanf("%d",&c[i]),num[c[i]]++;
memset(f,-1,sizeof(f));
cout<<dp(num[1],num[2],num[3],num[4],num[5],0)<<endl;
return 0;
}


by >_< NeighThorn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: