题目描述
有 N 头奶牛围绕着一个圆桌坐着,农夫FJ有
N 杯咖啡,第 i 杯咖啡的口味是tastei ,其中 tastei 是 A 或 B 或 C 三个字母之一。FJ给每头奶牛分配一杯咖啡(注意:第 i 头奶牛不一定是得到第i 杯咖啡,这是由农夫FJ决定的事情),FJ有一个条件:相邻的两头奶牛不能得到相同口味的咖啡,那么FJ总共有多少种不同的分配方案呢?答案模1,000,000,007。
输入格式 1711.in
多组测试数据。
第一行,一个整数 G ,表示有G 组测试数据。 1≤G≤5 。
每组测试数据格式如下:
第一行,一个整数 N 。3≤N≤50 。
第二行, N 个大写字母,第i 个字母表示第 i 杯咖啡的口味。
输出格式 1711.out
共
G 行,每行一个整数。
输入样例 1711.in
4
4
ABAB
5
ABABA
3
ABC
35
BCBABBACBABABCCCCCAABBAACBBBBCBCAAA
输出样例 1711.out
2
0
6
741380640
样例解释
第一组测试数据:
方案一:
第1头奶牛A,第2头奶牛B,第3头奶牛A,第4头奶牛B。
方案二:
第1头奶牛B,第2头奶牛A,第3头奶牛B,第4头奶牛A。
首先明确一点,我们的任务是给奶牛安排咖啡,因此我们关心的是如何分配,即各口味的咖啡数量是我们重点考虑的内容,因此输入时只需统计各口味的咖啡数量即可,位置不造成影响。
看到方案计数类问题,很自然地就会联想到dp。如何表示状态呢?如果只记录当前奶牛编号
i
和当前咖啡口味
于是我们用
f[i][j][A][B][C]
表示到前
i
头奶牛,其中第
状态的转移也非常容易,进行简单的分类讨论即可,共有6种情况:
- 第
i
杯取 A 口味,第
- 第
i
杯取 A 口味,第
- 第
i
杯取 B 口味,第
- 第
i
杯取 B 口味,第
- 第
i
杯取 C 口味,第
- 第
i
杯取 C 口味,第
再注意一下对杯数的限制,就可以了。总的时间复杂度为
O(n4)
(分类讨论不计)。
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const long long mod = 1e9 + 7;
const int maxn = 52;
int n;
int cnt[3];
int dp[maxn][3][maxn][maxn][maxn];
int main(void) {
freopen("1711.in", "r", stdin);
freopen("1711.out", "w", stdout);
int g;
cin >> g;
while (g--) {
int n;
cin >> n;
memset(cnt, 0, sizeof cnt);
for (int i = 0; i < n; i++) {
char ch;
cin >> ch;
++cnt[ch - 'A'];
}
long long ans = 0;
for (int start = 0; start < 3; start++) { //枚举第一杯咖啡的口味
if (!cnt[start]) continue; //没有此种咖啡,不考虑此种情况
memset(dp, 0, sizeof dp);
if (start == 0) dp[0][0][1][0][0] = 1;
else if (start == 1) dp[0][1][0][1][0] = 1;
else dp[0][2][0][0][1] = 1;
//以下是各种分类讨论
for (int i = 0; i + 1 < n; i++) {
for (int a = 0; a < cnt[0]; a++)
for (int b = 1; b <= cnt[1]; b++)
for (int c = 0; c <= cnt[2]; c++) {
dp[i + 1][0][a + 1][b][c] += dp[i][1][a][b][c];
dp[i + 1][0][a + 1][b][c] %= mod;
}
for (int a = 0; a < cnt[0]; a++)
for (int b = 0; b <= cnt[1]; b++)
for (int c = 1; c <= cnt[2]; c++) {
dp[i + 1][0][a + 1][b][c] += dp[i][2][a][b][c];
dp[i + 1][0][a + 1][b][c] %= mod;
}
for (int a = 1; a <= cnt[0]; a++)
for (int b = 0; b < cnt[1]; b++)
for (int c = 0; c <= cnt[2]; c++) {
dp[i + 1][1][a][b + 1][c] += dp[i][0][a][b][c];
dp[i + 1][1][a][b + 1][c] %= mod;
}
for (int a = 0; a <= cnt[0]; a++)
for (int b = 0; b < cnt[1]; b++)
for (int c = 1; c <= cnt[2]; c++) {
dp[i + 1][1][a][b + 1][c] += dp[i][2][a][b][c];
dp[i + 1][1][a][b + 1][c] %= mod;
}
for (int a = 1; a <= cnt[0]; a++)
for (int b = 0; b <= cnt[1]; b++)
for (int c = 0; c < cnt[2]; c++) {
dp[i + 1][2][a][b][c + 1] += dp[i][0][a][b][c] %= mod;
dp[i + 1][2][a][b][c + 1] %= mod;
}
for (int a = 0; a <= cnt[0]; a++)
for (int b = 1; b <= cnt[1]; b++)
for (int c = 0; c < cnt[2]; c++) {
dp[i + 1][2][a][b][c + 1] += dp[i][1][a][b][c];
dp[i + 1][2][a][b][c + 1] %= mod;
}
}
if (start == 0) (ans += (dp[n - 1][1][cnt[0]][cnt[1]][cnt[2]] + dp[n - 1][2][cnt[0]][cnt[1]][cnt[2]]) % mod) %= mod;
else if (start == 1) (ans += (dp[n - 1][0][cnt[0]][cnt[1]][cnt[2]] + dp[n - 1][2][cnt[0]][cnt[1]][cnt[2]]) % mod) %= mod;
else (ans += (dp[n - 1][0][cnt[0]][cnt[1]][cnt[2]] + dp[n - 1][1][cnt[0]][cnt[1]][cnt[2]]) % mod) %= mod;
}
printf("%lld\n", ans);
}
return 0;
}