Jesus Is Here HDU - 5459

2018TYUT暑期ACM模拟赛(10)
Jesus Is Here HDU - 5459
题意:求按照一定规律组成的字符串种所有cff,两两相距的距离。例如cffffcff。相距5。
思路:这道题写了挺久的,主要是写了一会儿又不想写了然后还是继续写,主要是找到递推式,找到了之后就出来了,至于是怎么发现这个递推式呢,是一点点从数据中发现的。
首先可以知道只要有c就有,cff所以可以记录c的位置,通过比较分析c的位置变化规律求出递推式。

用s[]表示答案,dis[]表示改字符串c位置到字符串末尾的距离和,sum[]表示改字符串c位置之和,ff[]是斐波那契数列,f[]也是斐波那契数列(两者一开始f[1],f[2]的值不同f[]表示c的个数,ff[]表示字符串的长度)。

求出的递推式是:
s[n]=s[n-1]+s[n-2]+dis[x-1]*f[x]+sum[x]*f[x-1];//n和x初始值不一样。

首先一段有规律的变化方便理解:

这里写图片描述

可以发现s[n]=s[n-1]+s[n-2]+((n-2)的每一个c位置到(n-1)的每一个c的位置)
就如:
s3=0
s4=0
s5=0+0+(2)*1+(3)*1
s6=0+5+(2)*2+(1+6)*1;
s7=5+16+(2+7)*3+(3+6+11)*2
s8=16+88+(2+7+10)*5+(1+6+11+14+19)*3

这里大家也发现了这是有一定规律的,而什么会有这样的规律是因为:当前串的答案,等于前两个串答案的和n-2的c到n-1的距离和(这个可以表示为dis[x-1]*f[x]+sum[x]*f[x-1] )

这里写图片描述
接下来就是找dis[] 和 sum[] 的规律:他们的递推式如下
dis[j-1]=(dis[j-2]+dis[j-3]+ff[j-2]*f[j-3]);
sum[j]=(sum[j-2]+sum[j-1]+ff[j-2]*f[j-1]);
这个的寻找也是根据字符串长度的变化的来
sum[]: 为上前两项和+(n-1前加入n-2会对n-1的c的位置的影响)n-2字符的长度*n-1c的个数
dis[]:前两项的和+(n-1前加入n-2会增加的 dis 是)n-1字符的长度*n-2c的个数

这里写图片描述

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
const ll mod=530600414;
const int N=201314+10;
ll dis[N],s[N],f[N],ff[N],sum[N];
int main()
{
    int t,kcase=0;
    scanf("%d",&t);
    int n;
    sum[1]=1,sum[2]=3;sum[3]=7;
    dis[1]=dis[2]=2;
    f[1]=f[2]=1;f[3]=2;
    ff[1]=3,ff[2]=5;ff[3]=8;
    s[3]=s[4]=0;s[5]=5;s[6]=16;
    for(int i=7,j=4;i<=201314;i++,j++)
    {
        f[j]=(f[j-2]+f[j-1])%mod;
        ff[j]=(ff[j-1]+ff[j-2])%mod;
        dis[j-1]=(dis[j-2]+dis[j-3]+ff[j-2]*f[j-3])%mod;
        sum[j]=(sum[j-2]+sum[j-1]+ff[j-2]*f[j-1])%mod;
        s[i]=s[i-1]+s[i-2]+(dis[j-1]*f[j])%mod+(sum[j]*f[j-1])%mod;
        s[i]%=mod;
    }
    while(t--)
    {
        scanf("%d",&n);
        printf("Case #%d: %lld\n",++kcase,s[n]);

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Miranda_ymz/article/details/81671066