hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=6153

题意:

给出两个字符串S1,S2,求S2的所有后缀在S1中出现的次数与其长度的乘积之和。

思路:

CCPC网络赛题解: https://post.icpc-camp.org/d/714-ccpc-2017

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277   是一样的

将s1,s2翻转,转化为求前缀在s1中出现的次数

next数组,记t[i]为长度为i的前缀出现的次数,显然t[n]=1。next[i]即为子串[0,i]的后缀与前缀重复的最长长度,因此可以统计一下next[i]的取值的个数,然后较长的前缀出现一次代表较短的前缀也一次,递推一下即可,复杂度为O(n)。

就是说统计所有在模式串中能匹配上的位置匹配了多少次,再通过fail指针逆推回去,因为长的前缀匹配上了,所有短的前缀也能匹配那么多次。

http://blog.csdn.net/algzjh/article/details/77415529  将S1,S2倒转,用KMP求得S2的fail数组,在S1上滑动的同时,累加结果。 这种是不对的

hack:

KMP好难啊!!! dalao的模板题,我没做出来 菜的一笔

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 1e6+10;
const int mod = 1e9+7;

char s[maxn],t[maxn];
int l1,l2,f[maxn];
ll ans,cnt[maxn];

void getfail(){
    f[0] = f[1] = 0;
    for(int i=1; i<l2; i++){
        int j = f[i];
        while(j && s[i]!=s[j]) j=f[j];
        f[i+1] = (s[i]==s[j]) ? j+1 : 0;
    }
}

int main(){
    int T = read();
    while(T--){
        scanf("%s%s",t,s);
        l1 = strlen(t), l2 = strlen(s);
        reverse(t,t+l1);
        reverse(s,s+l2);
        getfail();
        MS(cnt);
        int j=0;
        for(int i=0; i<l1; i++){
            while(j && t[i]!=s[j]) j=f[j];
            if(t[i] == s[j]) j++;
            ++cnt[j];
        }

        for(int i=l2; i>=0; i--){
            cnt[f[i]] += cnt[i];
            cnt[f[i]] %= mod;
        }
        ll ans = 0;
        for(int i=0; i<=l2; i++){
            ans = (ans+cnt[i]*i)%mod;
        }
        cout << ans << endl;
    }
}

错误代码[数据弱,可以AC]:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
char str[maxn],tt[maxn];
int nxt[maxn];
ll ans = 0;

void getnext(char *t)
{
    int len = strlen(t);
    nxt[0] = nxt[1] = 0;
    for (int i = 1; i < len; i++)
    {
        int j = nxt[i];
        while (j > 0 && t[i] != t[j]) j = nxt[j];
        nxt[i+1] = (t[i]==t[j]) ? j+1 : 0;
    }
}

void kmp(char *s, char *t)
{
    ll j = 0;
    ans = 0;
    int ll = strlen(s);
    int len = strlen(t);
    for (int i=0; i<ll; i++) {
        while (j > 0 && s[i] != t[j]) { ans+=((j*(j+1))/2)%mod; j=nxt[j];}
        if(s[i] == t[j]) j++;
        if(j == len) { ans+=((j*(j+1))/2)%mod; j = nxt[j];}
        if (ans >= mod)
            ans -= mod;
    }
    while(j >= 1){
        ans += (j*(j+1))/2;
        ans %= mod;
        j = nxt[j];
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        ans = 0;
        scanf("%s%s", str, tt);
        int l1 = strlen(str);
        int len = strlen(tt);
        for (int i = 0, j =  len - 1; i <= j; i++, j--)
            swap(tt[i], tt[j]);
        for (int i = 0, j =  l1 - 1; i <= j; i++, j--)
            swap(str[i], str[j]);
        // cout << str << " " << tt << endl;
        getnext(tt);

        kmp(str, tt);
        // for(int i=0; i<=len; i++)
        //     cout << nxt[i] << " ";
        // puts("");
        printf("%I64d\n", ans);
    }
    return 0;
}
时间: 2024-10-13 19:00:34

hdu6153 A Secret CCPC网络赛 51nod 1277 KMP的相关文章

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

2016 CCPC 网络赛 B 高斯消元 C 树形dp(待补) G 状压dp+容斥(待补) H 计算几何

2016 CCPC 网络赛 A - A water problem 水题,但读题有个坑,输入数字长度很大.. B - Zhu and 772002 题意:给出n个数(给出的每个数的质因子最大不超过2000),选出多个数相乘得b.问有多少种选法让b 为完全平方数. tags:高斯消元,求异或方程组解的个数.   好题 每个数先素数分解开.  对于2000以内的每个素数p[i],这n个数有奇数个p[i]则系数为1,偶数个则系数为0,最后n个数的p[i]系数异或和都要为0才会使得最后的积为完全平方数.

2018 CCPC网络赛

2018 CCPC网络赛 Buy and Resell 题目描述:有一种物品,在\(n\)个地点的价格为\(a_i\),现在一次经过这\(n\)个地点,在每个地点可以买一个这样的物品,也可以卖出一个物品,问最终赚的钱的最大值. solution 用两个堆来维护,一个堆维护已经找到卖家的,一个堆维护还没找到卖家的. 对于第\(i\)个地点,在已经找到卖家的堆里找出卖的钱的最小值,如果最小值小于\(a_i\),则将卖家换成\(i\),然后将原来的卖家放到没找到卖家的那里:如果最小值对于\(a_i\)

hdu 6152 : Friend-Graph (2017 CCPC网络赛 1003)

题目链接 裸的结论题.百度 Ramsey定理.刚学过之后以为在哪也不会用到23333333333,没想到今天网络赛居然出了.顺利在题面更改前A掉~~~(我觉得要不是我开机慢+编译慢+中间暂时死机,我还能再早几分钟过掉它 #include<bits/stdc++.h> using namespace std; int g[8][8]; int n; void solve() { for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) for

2018 CCPC网络赛 Dream&amp;&amp;Find Integer

首先这场比赛打得很难受,因为是第一次打网络赛而且也是比较菜的那种,所以对这场网络赛还是挺期待和紧张的,但是在做题的过程中,主要的压力不是来自于题目,更多的来自于莫干山...从12.40-2.00所有的题目都不判了,中间也就写了1003和1004但是都不知道结果就很难受, 然后一直不判就已经没什么看其他题的兴趣了,然后上床休息了一会,直到说杭电的评测机好了,之后才上去继续做题.然后..一直在写1001和1009..后面也没有写出来..直到比赛结束 首先说下1004 签到题竟然写了这么久,而且用了c

2019杭电多校&amp;CCPC网络赛&amp;大一总结

多校结束了, 网络赛结束了.发现自己还是太菜了,多校基本就是爆零和签到徘徊,第一次打这种高强度的比赛, 全英文,知识点又很广,充分暴露了自己菜的事实,发现数学还是很重要的.还是要多刷题,少玩游戏. 网络赛也打的不好, 开场写01,先是思路错,再是没考虑特判,直接罚时爆炸,再是写06,题意又看错,看了很久.其中队友过07, 我看08,队友03,08先乱写了个优先队列直接t,然后边吃边想,想到正解,忘记加换行... 最后看02, 也没写出来,队友03也是没调出来, 口上说着主攻数据结构,连想的算法都

2019 CCPC网络赛

一到网络赛,大家都是东亚之光 1001 00:23:46 solved by hl 签到 枚举一下位就行了 #include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset

51nod 1277 KMP 前缀出现次数

51NOD 1277:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277 跟HDU 6153还挺像的:http://www.cnblogs.com/Egoist-/p/7435573.html 相比与上面那个题,这个还要相对简单一些,只需要处理模式串自己就好了. 一开始写麻烦了,直接套了HDU6153的代码,后来发现--他就是个模式串本身的匹配,我干嘛弄那么麻烦Orz 题意:找前缀长度*出现次数的最大值,长度好说,

ccpc网络赛

1011:水题. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; const ll MOD=1e9+7; const double EPS=1e-13; ch