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