Jesus Is Here HDU - 5459(思维+数学递推)

Jesus Is Here HDU - 5459

I’ve sent Fang Fang around 201314 text messages in almost 5 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 s1=‘‘c” and the second one is s2=‘‘ff”.
The i-th message is si=si−2+si−1 afterwards. Let me give you some examples.
s3=‘‘cff”, s4=‘‘ffcff” and s5=‘‘cffffcff”.

I found the i-th message's utterly charming," Jesus said.
Look at the fifth message”. s5=‘‘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.
Input
An integer T (1≤T≤100), indicating there are T test cases.
Following T lines, each line contain an integer n (3≤n≤201314)
, as the identifier of message.
Output
The output contains exactly T lines.
Each line contains an integer equaling to:
∑i

题意:

规定一个字符串的递推关系,可以生成字符串递推关系为

s 1 = c

s 2 = f f

s i = s i 1 + s i 2

给定 1 n s n 中每个 c 两两之间的距离和取模(距离为两个不同的 c 下标相减)

i < j : s n [ i ] = s n [ j ] = c ( j i )   m o d   530600414

分析:

首先我们先写出前六个字符串观察一下:
1 : c
2 : f f
3 : c     f f
4 : f f     c f f
5 : c f f     f f c f f
6 : f f c f f     c f f f f c f f

我们设一个 a n s [ i ] c

我们根据上面写出的字符串首先可以得到

a n s [ i ] = a n s [ i 1 ] + a n s [ i 2 ] +   ?

也就是说如果我们知道 s i 1 s i 2 中的答案的话,最起码 s i 中得含有这两个答案的和

也就是前半部分 s i 2 c s i 1 c

那么我们差的部分 就是中间的连接部分,即 s i 2 c s i 1 c

因此问题转化成求解中间连接部分距离和取模


我们以 n = 6

这里写图片描述

如图所示,只需要计算红线标注的距离

实际上我们可以把求解中间完整长度的过程分解成求在 s 4 + s 5

即如下图
这里写图片描述
先求红色长度之和,在求黄色长度之和,再求和

对于红色长度之和,我们发现它们是 s 4 c

因此我们可以定义一个数组

d i s t [ i ] s i c

因此我们可以如果可以预处理出 d i s t [ i ] 红色部分的长度和就解决了

= d i s t × c

(因为后一个串中有几个c,前面的dist就需要加几次)

对于 d i s t [ i ] 的预处理我们后面说,先继续看黄色部分怎么算

我们发现其实黄色部分就是

s 5 c

那我们是不是需要在定义一个数组来记录每个c到字符串开头的距离之和呢?

不用!

我们使用减法就可以了

对于 s 5 , c = s 5 c s 5

因为我们已经有 d i s t [ i ] 了(c到字符串 s i

所以

= ( × c d i s t ) × c

通过上面的分析我们发现我们还用到了两个变量,一个是每个字符串的长度我们暂时用数组 l e n [ i ] 表示

二是每个字符串中 c c n t [ i ]

综上所述:

a n s [ i ] = a n s [ i 1 ] + a n s [ i 2 ] +   ?

? = d i s t [ i 2 ] × c n t [ i 1 ] + ( l e n [ i 1 ] × c n t [ i 1 ] d i s t [ i 1 ] ) × c n t [ i 2 ]


最后的任务就是分别预处理出数组 d i s t [ i ] , l e n [ i ] , c n t [ i ]

首先我们根据字符串 s i 的构成规则发现是斐波那契数列,因此其长度 l e n [ i ] c c n t [ i ] 的递推
是就是斐波那契数列递推式即:

l e n [ i ] = l e n [ i 1 ] + l e n [ i 2 ]

c n t [ i ] = c n t [ i 1 ] + c n t [ i 2 ]

对于 d i s t 的预处理仍然需要用到上面分段求解

对于后半部分字符串不用求了,需要求的就是前半部分的字符串中的每个c到新构成的字符串的末尾距离如图求绿色部分长度
这里写图片描述
仍然分成两段求解
这里写图片描述
前半部分就是前半部分字符串的dist,后半部分就是后半部分字符串的长度

所以

绿 = d i s t + × c

所以 d i s t

d i s t [ i ] = d i s t [ i 1 ] + d i s t [ i 2 ] + l e n [ i 1 ] × c n t [ i 2 ]


由此我们总结以下思路

首先预处理出 l e n [ i ] , c n t [ i ] , d i s t [ i ]
递推公式分别如下:

l e n [ i ] = l e n [ i 1 ] + l e n [ i 2 ]

c n t [ i ] = c n t [ i 1 ] + c n t [ i 2 ]

d i s t [ i ] = d i s t [ i 1 ] + d i s t [ i 2 ] + l e n [ i 1 ] × c n t [ i 2 ]

最后预处理出答案 a n s [ i ]

递推公式如下:

a n s [ i ] = a n s [ i 1 ] + a n s [ i 2 ]

+ d i s t [ i 2 ] × c n t [ i 1 ] + ( l e n [ i 1 ] × c n t [ i 1 ] d i s t [ i 1 ] ) × c n t [ i 2 ]

最后注意取模
code:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn = 201315;
const int mod = 530600414;
typedef long long ll;
ll ans[maxn];//记录答案
ll dist[maxn];//所有c到末尾的距离
ll cnt[maxn];//c的个数
ll len[maxn];//长度
void init(){
    len[1] = 1;
    len[2] = 2;
    cnt[1] = 1;
    cnt[2] = 0;
    for(int i = 3; i < maxn; i++){
        len[i] = (len[i-1] + len[i-2]) % mod;
        cnt[i] = (cnt[i-1] + cnt[i-2]) % mod;
    }

    dist[1] = dist[2] = 0;
    dist[3] = 2;
    for(int i = 4; i < maxn; i++){
        dist[i] = (dist[i-1] + (dist[i-2] + len[i-1] * cnt[i-2] % mod) % mod) % mod;
    }

    ans[1] = ans[2] = ans[3] = ans[4] = 0;
    for(int i = 5; i < maxn; i++){
        ans[i] = (ans[i-1] + ans[i-2]) % mod 
            + cnt[i-1] * dist[i-2] % mod 
            + cnt[i-2] * ((len[i-1] * cnt[i-1] % mod - dist[i-1] + mod) % mod) % mod;
        ans[i] %= mod;
    }
}
int main(){
    init();
    int cas = 1,t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("Case #%d: %lld\n",cas++,ans[n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/82220745
今日推荐