HDU-5459-递推&斐波那契

时间:2022-05-13 16:23:02

https://vjudge.net/contest/167883#problem/J
这道题的神奇之处在于发现他的答案的内在关系。因为考虑到老多的c和老多的c,所以我已开始以为是组合数学的东东。后来看了题解才恍然大悟,天下竟有如此之套路!
假设 每段中 c的个数 cnt
每段的长度 len
每段的c到终点的距离 dist
我们就会发现,所谓答案,(记录在dp里吧,555什么都往dp里存)
dp[]=dp[i-1]+dp[i-2]+cnt[i-1]cnt[i-2]+cnt[i-2](len[i-1]*cnt[i-1]-dist[i-1]).(这个计算相信你们是可以理解的。。
把所有的连接想象为一群线,首先把在 i-2段中的线计算出来。
每个 i-1对应一把,共cnt[i-1]*dist[i-2] 这么多,第二段同理。
但是要反着来,因为计算的 是c到他的头,不是尾巴的长度。

而dist[i]=dist[i-1]+dist[i-2]+dist[i-2]*len[i-1];
注意:要不断的mod。。

#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 len[maxn]; // 长度
void init() {
len[1]=1;len[2]=2;
for(int i=3;i<maxn;i++){
len[i]=(len[i-1]%mod+len[i-2]%mod)%mod;
}
cnt[2]=0;cnt[1]=1;
for(int i=3;i<maxn;i++){
cnt[i]=(cnt[i-1]%mod+cnt[i-2]%mod)%mod;
}
dist[1]=0;dist[2]=0;dist[3]=2;
for(int i=4;i<maxn;i++){
dist[i]=(dist[i-1]%mod+dist[i-2]%mod+(len[i-1]*cnt[i-2])%mod)%mod;
}
dp[1]=0;dp[2]=0;
dp[3]=dp[4]=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 * ((len[i-1] % mod * cnt[i-1] % mod) % mod -dist[i-1]) % 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;
}