斐波那契数列、DP——(HDU5459)Jesus Is Here 2015沈阳ICPC网络赛

3 篇文章 0 订阅

题目

I’ve sent Fang Fang around 201314201314 text messages in almost 55 years. Why can’t she make sense of what I mean? “But Jesus is here!” the priest intoned. “Show me your messages.” Fine, the first message is s[1] =“c” and the second one is s[2]=“ff”. The i-th message is s[i]=s[i-2]+s[i-1],afterwards. Let me give you some examples. s[3]= cff, s[4]=ffcff, s[5]=cffffcff. “I found the i-th message’s utterly charming”, Jesus said. “Look at the fifth message”. s[5]=cffffcff, and two ‘cff’appear in it. The distance between the first “cff” and the second one we said, is 5. “You are right, my friend,” Jesus said. “Love is patient, love is kind. It does not envy, it does not boast, it is not proud. It does not dishonor others, it is not self-seeking, it is not easily angered, it keeps no record of wrongs. Love does not delight in evil but rejoices with the truth. It always protects, always trusts, always hopes, always perseveres.” Listen - look at him in the eye. I will find you, and count the sum of distance between each two different “cff” as substrings of the message.

输入格式:T组输入,每组每行1个数字n∈[3,201314]。
输出格式:T行T个答案。答案i<j:sn[i…i+2]=sn[j…j+2]="cff"∑(j−i)mod530600414,where s[n] as a string corresponding to the n-th message.
样例输入:9
5
6
7
8
113
1205
199312
199401
201314
样例输出:
Case #1: 5
Case #2: 16
Case #3: 88
Case #4: 352
Case #5: 318505405
Case #6: 391786781
Case #7: 133875314
Case #8: 83347132
Case #9: 16520782

解析:(本题是算法题)

错误思路:试图找规律。
s[5]=c7ffffc2ff0, d12=5,D5=d12=5
s[6]=ffc10ffc7ffffc2ff0, d23=3,D6=d12+d23+d13=16
s[7]=c20ffffc15ffffc10ffc7ffffc2ff0,D7=(d12+d23+d34+d45) +(d13+d24+d35)+(d14+d25)+d15。
其中d12+d23=d13,d12+d23+d34=d14,d12+d23+d34+d45=d15。希望以此来找之后的规律,但是写到s[8]及之后的时候明显有问题->s[8]=353 5535,s[9]=5535 5353 5535,s[10]=3535 5353 5535 5353 5535。显然,5535和5353不是交替出现的,所以规律终止。

正确思路:按照斐波那契数列的思路来动态规划。
① 先构思整体:用dp数组来存答案,答案dp[i]=dp[i-1]+dp[i-2]+?,
即s[i]中任意两个cff的距离和=s[i-1]的距离和+s[i-2]的距离和+(s[i-2]中所有c到s[i-1]中所有c的距离和)。
② Cnt[i]表示s[i]中c的个数;
dis[i]表示s[i]中所有c到s[i]末尾(即最右边)的距离之和;
len[i]表示s[i]的长度。
③ 寻找“s[i-2]中所有c到s[i-1]中所有c的距离和”的关系:(以s[7]为例)
s[7]=(1)c7ffff(2)c2ff0|(中线为0点)f1f(3)c3ff(4)c6ffff(5)c11ff
对点1来说,有d13=7+3,d14=7+6,d15=7+11∴D1=d13+d14+d15=73+(3+6+11)。
对点2来说,有d23=2+3,d24=2+6,d25=2+11∴D2=d23+d24+d25=2
3+(3+6+11)。
∴“s[i-2]中所有c到s[i-1]中所有c的距离和”=D1+D2=(2+7)*3+(3+6+11)*2
又∵原来的dis[i-1]是从字符串最右边开始计数的,而上式的dis[i-1]是从中线处(即s[i-1]的最左边)开始计距离
∴上式s[i-1]中所有点c到s[i-2]中所有点c的距离和=len[i-1]*cnt[i-1]-dis[i-1]。(每个点到中线的距离=s[i-1]的总长度len[i-1]-该点到s[i-1]最右边的距离)
∵s[i-2]每个c点还是从最右边计距离的
∴上式s[i-2]中所有点c到s[i-1]中所有点c的距离和=dis[i-2]*cnt[i-1]。
综上,
dp[i]=dp[i-1]+dp[i-2]+(dis[i-2]cnt[i-1])+cnt[i-2](len[i-1]*cnt[i-1]-dis[i-1])。
④ 找其他子数组的规律(其实基本上都是斐波那契数列):
根据题目所给构造字符串的规律,s[i]=s[i-2]+s[i-1]
∴s[i]中点c的个数=s[i-2]中点c的个数+s[i-1]中点c的个数;
–>cnt[i]=cnt[i-2]+cnt[i-1];
s[i]的长度=s[i-2]的长度+s[i-1]的长度
–>len[i]=len[i-2]+len[i-1];
s[i]中所有点c到最右边的距离和=s[i-2]中所有点c到最右边的距离和+s[i-1]中所有点c到最右边的距离和+s[i-1]对s[i-2]的影响(每个点都多了s[i-1]的长度)
–>dis[i]=dis[i-2]+dis[i-1]+len[i-1]+cnt[i-2]。
⑤ 注意题目要求:每一步都要取模!!!

正确代码

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
const int mod=530600414;
const int maxn=201315;
ll dp[maxn],dis[maxn],cnt[maxn],len[maxn];
void init()
{
    len[1]=1,len[2]=2,len[3]=3,len[4]=5;
    cnt[1]=1,cnt[2]=0,cnt[3]=1,cnt[4]=1;
    dis[1]=0,dis[2]=0,dis[3]=2,dis[4]=2;
    dp[1]=0,dp[2]=0,dp[3]=0,dp[4]=0;
    for(ll i=5;i<maxn;i++)
    {
        len[i]=(len[i-1]%mod+len[i-2]%mod)%mod;
        cnt[i]=(cnt[i-1]%mod+cnt[i-2]%mod)%mod;
        dis[i]=(dis[i-1]%mod+dis[i-2]%mod+(len[i-1]%mod*cnt[i-2]%mod)%mod)%mod;
        dp[i]=(dp[i-1]%mod+dp[i-2]%mod+(dis[i-2]%mod*cnt[i-1]%mod)%mod+(cnt[i-2]%mod*((len[i-1]%mod*cnt[i-1]%mod)%mod-dis[i-1]%mod)%mod)%mod)%mod;
    }
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    for(ll i=1;i<=t;i++)
    {
        ll n;
        scanf("%lld",&n);
        printf("Case #%lld: %lld\n",i,dp[n]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值