HDU-5459-递推&斐波那契

来源:互联网 发布:java获取进程端口号 编辑:程序博客网 时间:2024/06/07 23:16

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;}
原创粉丝点击