8.4日字符串专题模拟赛

今天模拟赛T4数据锅了\所以全场没分

T2T3的数据极其强大

链接:

T1     T2    T3   T4

 

[ZJOI2009]对称的正方形

大致题意:给出一个矩形,求出所有的上下左右对称的正方形子矩阵个数(回文正方形)

考场就没细看,直接跳了

大概是二维马拉车,我们在处理时要上下求回文

 

 

[POI2012]OKR-A Horrible Poem

大致题意:给定一个字符串,然后有 m 次询问,每次给出一个区间 [ l , r ]  ,求出这个区间子串最短循环节。

最简单的想法就是将一个子串拆开,拆成  a + b , b + a 的样子(感性理解)

也就是找到最小的len使得 hash(l+len,r) == hash(l,r-len)

 

然后我们去枚质因子,加点卡常技巧就过了、

#include<bits/stdc++.h>

#define int long long
using namespace std;
const int N=5e5+7;
const int mod=1e9+7;
      
int n,m;
char a[N];
int h[N],mul[N],g[N];
bool vis[N];

vector<int >pri;

inline int read()
{
    register int x=0,f=1;register  char c=getchar();
    while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }
    while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); }
    return x*f;
}

inline void euler() 
{
    for(register int i=2;i<=n;i++) 
    {
        if(!vis[i])
        pri.push_back(i),g[i]=i;
        for (int j=0;j<pri.size()&&pri[j]*i<=n;j++) 
        {
            vis[pri[j]*i]=true,g[pri[j]*i]=pri[j];
            if (i%pri[j]==0)
                break;
        }
    }
    return ;
}

inline int get(int l,int r)
{    
    return ((h[r]-h[l-1]*mul[r-l+1])%mod+mod)%mod;    
}

signed main()
{
    
    n=read();
    for(register int i=1;i<=n;i++)
    cin>>a[i];
    
    euler();
    mul[0]=1;
    for(register int i=1;i<=n;i++)
    {
        mul[i]=mul[i-1]*233%mod;
        h[i]=(h[i-1]*233+a[i]-'a'+1)%mod;
    }
    
    cin>>m;
    
    while(m--)
    {
        register int x,y;
        x=read(),y=read();
        register int L=y-x+1;
        register int ans=L;
        if(get(x+1,y)==get(x,y-1))
        {
            cout<<1<<endl;    
            continue;
        }
        while(L-1)
        {
            if(get(x+ans/g[L],y)==get(x,y-ans/g[L]))
            ans/=g[L];
            L/=g[L];
        }
        cout<<ans<<endl;
    }
    
    return 0;
}

 

[POI2012]PRE-Prefixuffix

 大致题意:寻找最大前缀等于后缀

 Hash + 推理

1.L  < = n/2

2.我们可以手玩一个循环同构

比如(样例):

ab abba

abba ab

由于是从原本的串里挑前后缀串,所以我们考虑分别从头尾枚(删)

可以设:

line[i]为删去i个字符后剩余的最长相等前后缀

可以发现单调关系

 line[i+1]+≥  line[i

 相当于我们每往后考虑一个最多会比当前的最长前后缀长度少2(由1得)

 

自此我们可以倒序枚举 i ,来 O( n )求出line数组

然后大力一下即可

又由于此题数据原因:我们考虑双hash

 

#include<bits/stdc++.h>

#define int long long
using namespace std;
const int N=1e6+7;
const int mod=1e9+7;

int n;
char a[N];
int head[N],tail[N],mulh[N],mult[N];
int ans=0;
int line[N];//前缀去掉i个,剩余前后缀相等的 

bool pd(int x,int y, int l)
{
    if( (((int)((int)(head[x+l-1]-head[x-1]*mulh[l])%mod+mod)%mod)==((int)((int)(head[y+l-1]-head[y-1]*mulh[l])%mod+mod)%mod) )
    &&
        (((int)((int)(tail[x+l-1]-tail[x-1]*mult[l])%mod+mod)%mod)==((int)((int)(tail[y+l-1]-tail[y-1]*mult[l])%mod+mod)%mod)) )
    return 1;
    else
    return 0;
}


signed main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>a[i];
    
    mulh[0]=1;
    mult[0]=1;
    for(int i=1;i<=n;i++)
    {
        mulh[i]=mulh[i-1]*666%mod;
        mult[i]=mult[i-1]*2333%mod;
        head[i]=(head[i-1]*666+(a[i]-'a'+1))%mod;
        tail[i]=(tail[i-1]*2333+(a[i]-'a'+1))%mod;        
    }

    for(int L=n/2;L>=1;L--)
    {
        line[L]=min((n-2*L)/2,line[L+1]+2);    
        
        while(!pd(L+1,n-line[L]+1-L,line[L]))
        if(line[L])
        line[L]--;
        
    }           
    for(int L=1;L<=n/2;L++)
    {
        if(pd(1,n-L+1,L))
        ans=max(ans,line[L]+L);
    }
    
    cout<<ans;
    return 0;
}

 

 

[USACO15FEB]Censoring G

 大致题意:给定一个字符串,有m个我们需要在原字符串删除的单词。

不难从题意中得出:这是个AC自动机,题意很明确

那么... ...我们应该如何进行删除操作呢。。。

我们可以开两个栈,一个用于记录合法字符,另一个用于记录我们的AC自动机进程

当匹配到删除的单词,我们将两个栈同时删去单词。

每次放入被匹配字符串的一个字符。如果当前栈中字符数量大于等于匹配串的长度,开始匹配,如果有一个单词匹配失败,break掉,继续放字符。

 

#include<bits/stdc++.h>

using namespace std;
const int N=1e5+7;

int n;
struct node
{
    int son[30];
    int fail,cnt;
}a[N];

char s[N],c[N],st[N];
queue<int >q;
int g[N];

int _;
void init(int len)
{
    int x=0;
    for(int i=1;i<=len;i++)
    {
        if(a[x].son[c[i]-'a'])
        x=a[x].son[c[i]-'a'];
        else
        {
            _++;
            x=a[x].son[c[i]-'a']=_;
        }
    
    }
    a[x].cnt=len;
    return ;
}


void bfs()
{    
    int x=0;
    for(int i=0;i<=25;i++)
    {
        if(a[0].son[i])
        q.push(a[0].son[i]);
    }
    
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        
        for(int i=0;i<=25;i++)
        {
            if(a[x].son[i])
            {
                a[a[x].son[i]].fail=a[a[x].fail].son[i];
                q.push(a[x].son[i]);
            }
            else
            {
                a[x].son[i]=a[a[x].fail].son[i];    
            }
            
        }
        
    }
    
    return ;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>s+1;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>c+1;
        int len=strlen(c+1);
        init(len);
    }
    int len=strlen(s+1);
    bfs();
    int now=0,num=0;
    for(int i=1;i<=len;i++)
    {
        now=g[num];
        num++;
        st[num]=s[i];
        now=a[now].son[s[i]-'a'];
        g[num]=now;
        if(a[now].cnt)
        {
            for(int j=num-a[now].cnt+1;j<=num;j++)
            {
                st[j]=0;
                g[j]=0;
                num-=a[now].cnt;
            }
        }
        
        
    }
    for(int i=1;i<=num;i++)
    cout<<st[i];
    
    return 0;
}
/*
begintheescapexecutionatthebreakofdawn
 2
 escape
 execution
 */

 

posted @ 2021-08-04 16:31  Hehe_0  阅读(32)  评论(0)    收藏  举报