HDU 5459 Jesus Is Here(斐波那契递推 取模)

本文详细解析了HDU 5459 CFF题目的解题思路,采用递推方法求解字符串中字符'C'之间的距离之和问题。通过定义dp数组记录状态,并利用辅助数组cnt、dist和fibo进行状态转移,最终实现了高效的求解。
摘要由CSDN通过智能技术生成

题目链接: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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值