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

博客围绕HDU - 5459题目展开,规定字符串递推关系,要求计算给定字符串中每个'c'两两之间的距离和取模。通过分析字符串规律,将问题转化为求解中间连接部分距离和取模,需预处理dist[i]、len[i]、cnt[i]数组,最后得出答案递推公式并注意取模。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题意:

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

s1=cs1=c

s2=ffs2=ff

si=si1+si2si=si−1+si−2

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

i<j:sn[i]=sn[j]=c(ji) mod 530600414∑i<j:sn[i]=sn[j]=′c′(j−i) mod 530600414
分析:

首先我们先写出前六个字符串观察一下:
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]cans[i]数组,就用来存放题目要求的答案,即两两c距离和取模

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

ans[i]=ans[i1]+ans[i2]+ ?ans[i]=ans[i−1]+ans[i−2]+ ?

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

也就是前半部分si2csi1csi−2中各个c距离之和取模,和后半部分si−1中各个c距离之和取模

那么我们差的部分就是中间的连接部分,即si2csi1c

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


我们以n=6n=6的字符串为例子来说明计算中间连接部分递推的过程

这里写图片描述

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

实际上我们可以把求解中间完整长度的过程分解成求在s4+s5s4中的长度+在s5中的长度

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

对于红色长度之和,我们发现它们是s4cs4中每个c到字符串末尾的距离之和

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

dist[i]sicdist[i]:代表字符串si中所有字符c到字符串末尾的距离之和

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

=dist×c红色部分长度和=前一个串的dist×后一个串中c的个数

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

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

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

s5cs5中每个c到字符串开头的距离(请忽略上图两个字符串间的空白,我是为了好区分两个字符串)

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

不用!

我们使用减法就可以了

对于s5,c=s5cs5s5,每个c到开头位置的距离=s5的长度−c到s5末尾的距离

因为我们已经有dist[i]dist[i]了(c到字符串sisi末尾距离之和

所以

=(×cdist)×c黄色部分的长度和=(后一个串的长度×后一个串中c的个数−后一个串的dist)×前一个串c的个数

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

二是每个字符串中ccnt[i]c的个数我们暂时用cnt[i]来表示

综上所述:

ans[i]=ans[i1]+ans[i2]+ ?ans[i]=ans[i−1]+ans[i−2]+ ?

?=dist[i2]×cnt[i1]+(len[i1]×cnt[i1]dist[i1])×cnt[i2]?=dist[i−2]×cnt[i−1]+(len[i−1]×cnt[i−1]−dist[i−1])×cnt[i−2]

最后的任务就是分别预处理出数组dist[i],len[i],cnt[i]dist[i],len[i],cnt[i]

首先我们根据字符串sisi的构成规则发现是斐波那契数列,因此其长度len[i]ccnt[i]len[i]和c的个数cnt[i]的递推
是就是斐波那契数列递推式即:

len[i]=len[i1]+len[i2]len[i]=len[i−1]+len[i−2]

cnt[i]=cnt[i1]+cnt[i2]cnt[i]=cnt[i−1]+cnt[i−2]

对于distdist的预处理仍然需要用到上面分段求解

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

所以

绿=dist+×c绿色部分的总和=前半部分字符串的dist+后半部分字符串的长度×前半部分c的个数

所以distdist数组的预处理递推式为

dist[i]=dist[i1]+dist[i2]+len[i1]×cnt[i2]dist[i]=dist[i−1]+dist[i−2]+len[i−1]×cnt[i−2]

由此我们总结以下思路

首先预处理出len[i],cnt[i],dist[i]len[i],cnt[i],dist[i]
递推公式分别如下:

len[i]=len[i1]+len[i2]len[i]=len[i−1]+len[i−2]

cnt[i]=cnt[i1]+cnt[i2]cnt[i]=cnt[i−1]+cnt[i−2]

dist[i]=dist[i1]+dist[i2]+len[i1]×cnt[i2]dist[i]=dist[i−1]+dist[i−2]+len[i−1]×cnt[i−2]

最后预处理出答案ans[i]ans[i]

递推公式如下:

ans[i]=ans[i1]+ans[i2]ans[i]=ans[i−1]+ans[i−2]

+dist[i2]×cnt[i1]+(len[i1]×cnt[i1]dist[i1])×cnt[i2]+dist[i−2]×cnt[i−1]+(len[i−1]×cnt[i−1]−dist[i−1])×cnt[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值