题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5459
比赛的时候把每个c的位置的到下一个c位置的距离算出来,想着怎么去求和,结果卡死在上面了。然后后来就一直在想出题者和cff的关系了。。。
赛后仔细琢磨了一下,觉得这种题就应该从递推的角度去分析, 1A.
首先定义dp[i]表示整数i对应的答案,那么就会有dp[i] = dp[i-2] + dp[i-1] + ?, 关键在于?要怎么解决。 明确“?”表示s[i-2]中所有c到s[i-1]的所有c的距离之和。
我们定义数组cnt[i]表示s[i]中c的个数,dist[i]表示s[i]中所有c到s[i]末尾的距离之和。
那么“?”= cnt[i-1] * dist[i-2] + cnt[i-2] * (len[i] - dist[i-1]),特别注意,在dist数组计算距离时,我可以选择包含c或者不包含c,dist[i]包含了c,那么len[i] - dist[i] 就不包含了。
同时易知len[i]也是一个斐波那契数列。
字符串为:s[i] = s[i-2] + s[i-1], + 表示连接。
有转移方程为:dp[i] = dp[i-2] + dp[i-1] + cnt[i-1] * dist[i-2] + cnt[i-2] * (len[i] - dist[i-1]);
dist[i] = dist[i-1] + dist[i-2] + len[i-1] * cnt[i-2];
cnt[i] = cnt[i-1] + cnt[i-2];
len[i] = len[i-1] + len[i-2];
最后注意步步取模。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
using namespace std;
const int maxn = 201315;
const int mod = 530600414;
typedef long long LL;
LL dp[maxn]; // 答案
LL dist[maxn]; // 所有c到末尾的距离
LL cnt[maxn]; // c的个数
LL fibo[maxn]; // 长度
void init() {
fibo[1] = 1, fibo[2] = 2;
cnt[1] = 1, cnt[2] = 0;
for (int i = 3; i < maxn; i ++) {
fibo[i] = (fibo[i-1] % mod + fibo[i-2] % mod) % mod;
cnt[i] = (cnt[i-1] % mod + cnt[i-2] % mod) % mod;
}
dist[1] = dist[2] = 0, dist[3] = 2;
for (int i = 4; i < maxn; i ++) {
dist[i] = (dist[i-1] % mod + dist[i-2] % mod + (fibo[i-1] % mod * cnt[i-2] % mod) % mod) % mod;
}
dp[4] = dp[1] = dp[2] = dp[3] = 0;
for (int i = 5; i < maxn; i ++) {
dp[i] = (dp[i-2] % mod + dp[i-1] % mod
+ (cnt[i-1] % mod * dist[i-2] % mod) % mod
+ (cnt[i-2] % mod * ((fibo[i-1] % mod * cnt[i-1] % mod) % mod - dist[i-1] % mod) % mod) % mod) % mod;
}
}
int main() {
init();
int cas = 1, t, n;
scanf("%d", &t);
while (t --) {
scanf("%d", &n);
printf("Case #%d: ", cas ++);
printf("%I64d\n", dp[n]);
}
return 0;
}