hdu 6153 A Secret(最简洁的代码)

A Secret
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 500 Accepted Submission(s): 199

Problem Description

Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell:
Suffix(S2,i) = S2[i…len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li.
Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.

Input

Input contains multiple cases.
The first line contains an integer T,the number of cases.Then following T cases.
Each test case contains two lines.The first line contains a string S1.The second line contains a string S2.
1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.

Output

For each test case,output a single line containing a integer,the answer of test case.
The answer may be very large, so the answer should mod 1e9+7.

Sample Input

2
aaaaa
aa
abababab
aba

Sample Output

13
19
Hint

case 2:
Suffix(S2,1) = “aba”,
Suffix(S2,2) = “ba”,
Suffix(S2,3) = “a”.
N1 = 3,
N2 = 3,
N3 = 4.
L1 = 3,
L2 = 2,
L3 = 1.
ans = (3*3+3*2+4*1)%1000000007.

解题思路:

 俩天的时间,游览量100+,本来只是自己记录一下,但是既然有人看,那我好好说一下把。
 第一个字符串为S,第二个T。要找T的所有后缀在S中出现的次数和对应串长度的积的和。


 比赛的时候就有思路,奈何kmp很渣,比赛完,看了看kmp就写出来了。
 首先要求出现次数,第一想法就是拿后缀一一去主串中找出现的次数,用kmp应该快点,但是数据有10的6次方,说实话
 kmp的复杂度还是蛮高的。肯定要超时。

 于是,我就脑子里过了一下暴力的过程,灵光一闪,如果最长的匹配成功,那么短的不就也匹配了一次吗,刚好kmp不是一位一位匹配的吗?我只要找最长的串,在主串中出现的次数,那么在匹配的过程中,我就可以知道他的每个后缀出现次数,但是正着匹配,会出现遗漏,于是我就继续想。

 观察了一下,字符串T,如果把T反转一下,那么后缀就变为前缀,刚好符合kmp匹配过程。。。ok
 因为
 T反转,所以S也要反转,这个比较好想了。
 画个图,应该挺好理解的。

总结:反转俩个字符串,用kmp找T在S中出现的次数,每匹配一位成功,就代表那一位后缀出现加一。思路就这样,稍稍改改kmp的板子就行。

写了这么多,如果有错误,请指教,有疑惑,请留言,觉得有点帮助,点个赞。

代码:

#include <cstdio>  
#include <cstring>  

using namespace std;  

const int mod = 1e9 + 7;
const int N = 1000111;  
int next[N];  //跳转数组
long long ans[N]; //记录每个后缀出现次数
char S[N], T[N];  
int slen, tlen;  //俩个串的长度
long long sum = 0; //答案

void getNext()  
{  
    int j, k;  
    j = 0; k = -1; next[0] = -1;  
    while(j < tlen)  
        if(k == -1 || T[j] == T[k])  
            next[++j] = ++k; 
        else  
            k = next[k];  
}

void KMP_Count()  
{ 
    int i, j = 0; 
    S[slen] = '#'; S[slen+1] = 0;
    getNext();  
    for(i = 0; i < slen+1; i++)  
    {  
        while(j && S[i] != T[j])  
        {
            ans[j]++;
            j = next[j];
        }
        if(S[i] == T[j])  
        {
            j++;
        }  
        if(j == tlen)  
        {
            ans[j]++;
            j = next[j];
        }  
    }

    for(long long i = tlen;i >= 0;i--) //按照题目要求求和
    {
        ans[i] += ans[i+1];
        sum = (sum % mod +  (ans[i]%mod * i%mod) % mod) % mod;
    }
    printf("%lld\n",sum);
}  

int main()  
{  
    int TT;  
    int i, cc;  
    scanf("%d",&TT); 
    while(TT--)  
    {  
        sum = 0;
        memset(S,0,sizeof(T));
        memset(S,0,sizeof(S));
        memset(next,0,sizeof(next));
        memset(ans,0,sizeof(ans)); //初始化
        scanf("%s",S);
        scanf("%s",T);  
        memset(ans,0,sizeof(ans));

        strrev(S);
        strrev(T);//反转字符串

        slen = strlen(S);  
        tlen = strlen(T);  

        KMP_Count();
    }  
    return 0;  
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值