Codeforces 535D - Tavas and Malekas

535D - Tavas and Malekas

题目大意:给你一个模板串,给你一个 s 串的长度,告诉你 s 串中有 m 个模板串并告诉你,他们的其实位置,

问你这样的 s 串总数的多少,答案对1e9+7取模。

我感觉我英语是不是不行啊,我以为他的意思是他里面一共只有m个匹配串,想着没有其他的匹配串,感觉

好麻烦好麻烦好麻烦啊!!!!!!

思路:最暴力的思路,他给你一个匹配串的位置,你就在s串上更新,如果遇到没有已经被更新而且字符不同时

输出0,然后统计剩下的未知字符的个数x,答案就是 (26^x)%mod。这样可能会超时,我今天学习了一波

KMP(看毛片)算法,这玩意真的有点难理解,以后多理解几遍。

我们可以在更新s串的时候只更新后面没有更新的,然后用kmp扫一遍,看m个匹配串是否都出现过就好了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5;
const ll mod=1e9+7;
char s[N],t[N];
int nx[N];
int len1,len2,n,m,w[N],c=0;
void get_next()
{
    int k=0;
    for(int i=1;i<len2;i++)
    {
        while(k>0 && t[k]!=t[i]) k=nx[k-1];
        if(t[k]==t[i]) k++;
        nx[i]=k;
    }
}
void kmp()
{
    int k=0;
    for(int i=0;i<n;i++)
    {
        while(k>0 && t[k]!=s[i]) k=nx[k-1];
        if(t[k]==s[i]) k++;
        if(k==len2)
        {
            if(binary_search(w,w+m,i-k+1)) c++;
        }
    }
}
int main()
{
    cin>>n>>m;
    scanf("%s",t);
    len2=strlen(t);
    for(int i=0;i<n;i++) s[i]=‘?‘;
    s[n]=‘\0‘;
    for(int i=0;i<m;i++) scanf("%d",&w[i]),w[i]-=1;
    sort(w,w+m);
    m=unique(w,w+m)-w;
    int last=-1;
    for(int i=0;i<m;i++)
    {
        if(w[i]+len2-1>last)
        {
            int start=w[i],dis=0;
            if(last+1>w[i])
            {
                dis=last+1-w[i];//dis为相对模板串开头的偏移位置。
                start=last+1;
            }
            for(int j=start;j<=w[i]+len2-1;j++) s[j]=t[j-start+dis];
            last=w[i]+len2-1;
        }
    }
    //puts(s);
    get_next();
    kmp();
    if(c<m)
    {
        puts("0");
        return 0;
    }
    ll res=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]==‘?‘) res+=1;
    }
    ll ans=1;
    for(int i=1;i<=res;i++)
    {
        ans=(ans*(ll)26)%mod;
    }
    cout<<ans<<endl;
    return 0;
}

时间: 2024-10-14 02:12:05

Codeforces 535D - Tavas and Malekas的相关文章

codeforces 535D. Tavas and Malekas KMP

题目链接 又复习了一遍kmp....之前都忘光了 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_pair(x, y) 6 #define lson l, m, rt<<1 7 #define mem(a) memset(a, 0, sizeof(a)) 8 #define rson

Codeforces 536B Tavas and Malekas 求自身首尾的重叠位置 KMP

题目链接:点击打开链接 题意: 用小写字母构造n长的串S,m个要求 字符串P 下面m个位置.a1, a2···am(输入有序) 要使得字符串S的以ai 开头且后面是一个P串. 问构造的方法数 思路: 实际上,对于ai, ai+1 ,两个位置,如果这两个位置会相互影响(即 ai+1 - ai < len) 复制一个和P一样的串P' 把P放在ai位置,把P'放在ai+1位置,那么只需要判断一下 P的后半段是否和P'的前半段匹配即可. 也就是P'的哪些位置是和P的尾部相同的. KMP求出这些位置放到s

【Codeforces 536B】Tavas and Malekas

536B Tavas and Malekas 题意:给一个字符串,现在要把这个字符串在一个大空字符串中放多次,每一次的开头在\(p_i\)位置,然后现在问这个大字符串有多少种情况. 思路:首先如果两个字符串放置的位置有重叠,重叠部分必须相等. 那么就是一个前缀要等于一个后缀. 所以果断z function.这样的话写起来比kmp快... 然后就可以对于每两个连续出现判断这些重复部分的交叉状况,同时算上所有的非自由的字符,最后求出\(2^{自由字符数量}\)即可. 原文地址:https://www

Codeforces Round #299 (Div. 2)D. Tavas and Malekas

KMP,先预处理按每个节点标记,扫一遍更新每个匹配位置,最后kmp判断是否有重合而且不相同的地方 注意处理细节,很容易runtime error #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #inclu

codeforces535D:Tavas and Malekas(KMP)

Tavas is a strange creature. Usually "zzz" comes out of people's mouth while sleeping, but string s of length n comes out from Tavas' mouth instead. Today Tavas fell asleep in Malekas' place. While he was sleeping, Malekas did a little process o

Codeforces 535C Tavas and Karafs

题目链接:CF - 535C Karafs is some kind of vegetable in shape of an 1 × h rectangle. Tavaspolis people love Karafs and they use Karafs in almost any kind of food. Tavas, himself, is crazy about Karafs. Each Karafs has a positive integer height. Tavas has

Codeforces B - Tavas and SaDDas

535B - Tavas and SaDDas 方法一:打表大法. 代码1: #include<bits/stdc++.h> using namespace std; int a[1024]={0,4,7,44,47,74,77,444, 447,474,477,744,747,774,777, 4444,4447,4474,4477,4744,4747,4774, 4777,7444,7447,7474,7477,7744,7747, 7774,7777,44444,44447,44474,

Codeforces 535C Tavas and Karafs(二分)

题意  有一个等差数列  从A开始  公差为B  然后n个询问  每个询问给定l,t,m   然后要求如果每次可以最多选择m个数   使这m个数-1   那么在t次操作中可以使l为左端点的最长序列中使所有数为0  输出这个最长序列的右端序号 定理  序列h1,h2,...,hn 可以在t次时间内(每次至多让m个元素减少1)  全部减小为0  当且仅当 max(h1, h2, ..., hn) <= t  &&  h1 + h2 + ... + hn <= m*t    那么就可

CodeForces 535C Tavas and Karafs —— 二分

题意:给出一个无限长度的等差数列(递增),每次可以让从l开始的m个减少1,如果某个位置已经是0了,那么可以顺延到下一位减少1,这样的操作最多t次,问t次操作以后从l开始的最长0序列的最大右边界r是多少. 分析:由题意可以挖掘出两个条件:l~r中最大的值(因为是递增的,即r的值)必定不大于t:同时,t*m要大于或等于这一段的和.那么根据这两个条件进行二分即可. 细节:二分的右端点inf不能设置的太大,否则第一次的mid可能就会爆long long. 代码如下: 1 #include <stdio.