个人博客链接:​​https://blog.nuoyanli.com/2020/04/02/fuz2204/​

原题链接

​http://acm.fzu.edu.cn/problem.php?pid=2204​

题意

给出FUZ-2204-7环形dp_#define个小球,每个小球只能涂黑色或者是白色,规定FUZ-2204-7环形dp_#include_02个连续的不能是同种颜色,问有多少种涂色方法?答案取模FUZ-2204-7环形dp_#define_03

思路

我们将问题变成,求用FUZ-2204-7环形dp_#include_04组成长度为FUZ-2204-7环形dp_#define的环,环中不能超过有连续FUZ-2204-7环形dp_#include_02FUZ-2204-7环形dp_#include_07FUZ-2204-7环形dp_#define_08的方案数,答案FUZ-2204-7环形dp_ios_09

首先,这是环形FUZ-2204-7环形dp_ios_10是毋容置疑的,我们先抛开环形这个问题考虑线形的FUZ-2204-7环形dp_ios_10

  • FUZ-2204-7环形dp_#include_12表示到第FUZ-2204-7环形dp_#include_13个位置,FUZ-2204-7环形dp_#include_13这个位置种类为FUZ-2204-7环形dp_#define_15的组成的方案数,又因为FUZ-2204-7环形dp_ios_16FUZ-2204-7环形dp_#include_17的情况是一样的,所以任取一种做FUZ-2204-7环形dp_#include_18答案FUZ-2204-7环形dp_#define_19即可。
  • 状态转移
for (int i = 1; i <= n; i++) {
dp[i][0] = 1;
for (int j = 0; j < 2; j++) {
for (int k = 1; k < min(i, 7); k++) {
dp[i][j] = (dp[i][j] + dp[i - k][!j]) % mod;
}
}
}

现在回归到环形这个限制,对于上面推的状态显然是具有后效性的,涉及到重复计算,拆环我们可以考虑枚举起点的状态:

  • 由于先前说的FUZ-2204-7环形dp_#include_17FUZ-2204-7环形dp_ios_16的状态是对应的,我们以FUZ-2204-7环形dp_ios_16为例枚举起点的状态

1

10
100
1000
10000
100000
1000000

  • 我们之后的所有状态都可以由上面这些两两拼接。
  • 最后我们计算结果的时候,如果结尾和开头枚举的物品种类相同,要保证答案合法那么只需要保证结尾连续的个数+开头连续的个数FUZ-2204-7环形dp_ios_23即可。

与线形的相比,状态转移不变,就多枚举了开始位置和状态而已。

参考代码

#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>

//#include <bits/stdc++.h>
using namespace std;
#define
#define
#define
#define
#define
//#define in
#define
#define
#define
#define
const double pi = acos(-1.0);
const double eps = 1e-9;
typedef long long LL;
const int N = 1e5 + 10;
const int M = 1e3 + 10;
const int mod = 2015;
const LL inf = 0x3f3f3f3f;
const double f = 2.32349;
LL dp[N][2], n, t;
void solve() {
IOS;
int k = 0;
cin >> t;
while (t--) {
cin >> n;
cout << "Case #" << ++k << ": ";
LL ans;
if (n <= 6) {
ans = 1;
for (int i = 1; i <= n; i++) {
ans = (ans + ans) % mod;
}
} else {
ans = 0;
for (int st = 1; st < 7; st++) {
memset(dp, 0, sizeof(dp));
dp[st][0] = 1;
for (int i = st + 1; i <= n; i++) {
for (int j = 0; j < 2; j++) {
if (i == n && j == 0) {
for (int k = 1; k < min(i, 7 - st); k++) {
dp[i][j] = (dp[i][j] + dp[i - k][!j]) % mod;
}
} else {
for (int k = 1; k < min(i, 7); k++) {
dp[i][j] = (dp[i][j] + dp[i - k][!j]) % mod;
}
}
}
}
ans = (ans + dp[n][0] + dp[n][1]) % mod;
}
ans = (ans * 2) % mod;
}
cout << ans << endl;
}
}
signed main() {
#ifdef
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
solve();
return 0;
}