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
题意:
规定一个字符串的递推关系,可以生成字符串递推关系为
给定1个n1个n求snsn中每个cc两两之间的距离和取模(距离为两个不同的下标相减)
即
分析:
首先我们先写出前六个字符串观察一下:
1:c1:c
2:ff2:ff
3:c ff3:c ff
4:ff cff4:ff cff
5:cff ffcff5:cff ffcff
6:ffcff cffffcff6:ffcff cffffcff
我们设一个ans[i]数组,就用来存放题目要求的答案,即两两c距离和取模ans[i]数组,就用来存放题目要求的答案,即两两c距离和取模
我们根据上面写出的字符串首先可以得到
也就是说如果我们知道si−1和si−2si−1和si−2中的答案的话,最起码sisi中得含有这两个答案的和
也就是前半部分si−2中各个c距离之和取模,和后半部分si−1中各个c距离之和取模si−2中各个c距离之和取模,和后半部分si−1中各个c距离之和取模
那么我们差的部分??就是中间的连接部分,即
因此问题转化成求解中间连接部分距离和取模
我们以n=6的字符串为例子来说明计算中间连接部分递推的过程n=6的字符串为例子来说明计算中间连接部分递推的过程
如图所示,只需要计算红线标注的距离
实际上我们可以把求解中间完整长度的过程分解成求在s4中的长度+在s5中的长度s4中的长度+在s5中的长度
即如下图
先求红色长度之和,在求黄色长度之和,再求和
对于红色长度之和,我们发现它们是s4中每个c到字符串末尾的距离之和s4中每个c到字符串末尾的距离之和
因此我们可以定义一个数组
dist[i]:代表字符串si中所有字符c到字符串末尾的距离之和dist[i]:代表字符串si中所有字符c到字符串末尾的距离之和
因此我们可以如果可以预处理出dist[i]dist[i]红色部分的长度和就解决了
(因为后一个串中有几个c,前面的dist就需要加几次)
对于dist[i]dist[i]的预处理我们后面说,先继续看黄色部分怎么算
我们发现其实黄色部分就是
s5中每个c到字符串开头的距离(请忽略上图两个字符串间的空白,我是为了好区分两个字符串)s5中每个c到字符串开头的距离(请忽略上图两个字符串间的空白,我是为了好区分两个字符串)
那我们是不是需要在定义一个数组来记录每个c到字符串开头的距离之和呢?
不用!
我们使用减法就可以了
对于s5,每个c到开头位置的距离=s5的长度−c到s5末尾的距离s5,每个c到开头位置的距离=s5的长度−c到s5末尾的距离
因为我们已经有dist[i]dist[i]了(c到字符串si末尾距离之和si末尾距离之和)
所以
通过上面的分析我们发现我们还用到了两个变量,一个是每个字符串的长度我们暂时用数组len[i]len[i]表示
二是每个字符串中c的个数我们暂时用cnt[i]来表示c的个数我们暂时用cnt[i]来表示
综上所述:
最后的任务就是分别预处理出数组dist[i],len[i],cnt[i]dist[i],len[i],cnt[i]
首先我们根据字符串sisi的构成规则发现是斐波那契数列,因此其长度len[i]和c的个数cnt[i]len[i]和c的个数cnt[i]的递推
是就是斐波那契数列递推式即:
对于distdist的预处理仍然需要用到上面分段求解
对于后半部分字符串不用求了,需要求的就是前半部分的字符串中的每个c到新构成的字符串的末尾距离如图求绿色部分长度
仍然分成两段求解
前半部分就是前半部分字符串的dist,后半部分就是后半部分字符串的长度
所以
所以dist数组的预处理递推式为dist数组的预处理递推式为
由此我们总结以下思路
首先预处理出len[i],cnt[i],dist[i]len[i],cnt[i],dist[i]
递推公式分别如下:
最后预处理出答案ans[i]ans[i]
递推公式如下:
最后注意取模
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;
}