您的位置:首页 > 其它

FOJ 2204 dp

2015-10-22 20:26 295 查看
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2204

我次奥。。。dp渣的要吐血了,这题想了挺久。。。

题意:给出n(0 <= n <= 10^5)个球,每个球可以是黑色或者白色,求所有的涂色方法,要求把这些球围成一个圈以后,没有连续的7个白球或者黑球。。。

思路:dp方程是dp[i][j][k]表示用第i个颜色(0或1)放到第j个位置的话,从当前点往前有连续的k个i颜色的小球。

然后枚举开头的同颜色的小球数目,看做是枚举了那么多小球后再用不同颜色的小球分开,假设一开始枚举了n个0这种颜色的小球,那么对于当前的枚举只要将sum(dp[0]
[k]) k <= 6 - n 和 sum(dp[1]
[k]) k <= 6加起来,最后再乘以2(相当于一开始小球的颜色不同)就可以了。。。。。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 100005;
const int mod = 2015;

int n;
int dp[2][maxn][8];
void add(int &a,int &b)
{
a += b;
a %= mod;
}
void cal(int t)
{
mem(dp,0);
dp[0][t][1] = 1;
for(int i = t;i <= n;i++)
{
for(int j = 1;j <= 5;j++)
{
add(dp[1][i + 1][1],dp[0][i][j]);
add(dp[0][i + 1][1],dp[1][i][j]);
add(dp[0][i + 1][j + 1],dp[0][i][j]);
add(dp[1][i + 1][j + 1],dp[1][i][j]);
}
add(dp[1][i + 1][1],dp[0][i][6]);
add(dp[0][i + 1][1],dp[1][i][6]);
}
}

int main()
{
int T;
scanf("%d",&T);
for(int cas = 1;cas <= T;cas++)
{
scanf("%d",&n);
printf("Case #%d: ",cas);
if(n <= 6){
int sum = 0;
for(int i = 1;i <= n;i++){
if(i == 1)sum = 1;
sum = sum * 2;
}
printf("%d\n",sum);
continue;
}
int sum = 0;
for(int i = 2;i <= 7;i++)
{
cal(i);
int temp = 0;
for(int j = 1;j <= 7 - i;j++)
{
temp += dp[1]
[j];
}
for(int j = 1;j <= 6;j++)
temp += dp[0]
[j];
temp = temp * 2;
sum += temp % mod;
sum %= mod;
}
while(sum < 0)sum += mod;
printf("%d\n",sum);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: