专项测试(字符串2)

专项测试(字符串2)

所以这是Niuma题嘛??

开场第一题没看懂题面,然后愣了一会

溜了一眼第二题,发现前两个都是子串问题,然后心态崩了,去看第三题

于是沉浸于小故事中,于是第三题也不会做,打了个背包就跑了

回来看第一题,看看\(OJ\)上的图片,明白了题意

然后仍旧不会做,就去看第二题了,然后切了第二题

此时剩下两个小时,只有\(110pts\),虽然最后也只有这些分

第一题有思路,就开打了,测样例的时候发现根本对不上

然后我认为是样例错了,开玩了

临近结束\(15min\)的时候,发现第一题应该是子串而不是后缀,于是我假了,于是不想做了

T1 CF1063F

依旧是\(DP\),枚举起点,有一大堆性质,然后保证了复杂度是\(\mathcal{O(nlogn)}\)

用反串建立后缀树,用线段树+\(DFS\)序维护子树最大值,因为一个点代表的串是它子树内的串的前缀

于是这个题做完了

然而卡常的\(OJ\)并不想让你就这样过了,于是你需要一个\(\mathcal{O(n\sqrt{n})}\)的高级做法

直接哈希判断是否相等,因为数据是随的,于是连\(log\)都跑不满,就过了

nlogn
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=5e5+5;
int n,ans;
char a[N];
struct SAM{
    struct POT{
        int len,fail,son[27];
    }tr[N*2];
    int seg,las;
    SAM(){seg=las=1;tr[0].len=-1;}
    struct XDS{
        #define ls x<<1
        #define rs x<<1|1
        int mx[N*8];
        void pushup(int x){mx[x]=max(mx[ls],mx[rs]);}
        void ins(int x,int l,int r,int pos,int v){
            if(l==r)return mx[x]=v,void();
            int mid=l+r>>1;
            if(pos<=mid)ins(ls,l,mid,pos,v);
            else ins(rs,mid+1,r,pos,v);
            pushup(x);return ;
        }
        int query(int x,int l,int r,int ql,int qr){
            if(ql>qr)return -1;
            if(ql<=l&&r<=qr)return mx[x];
            int mid=l+r>>1,ret=0;
            if(ql<=mid)ret=max(ret,query(ls,l,mid,ql,qr));
            if(qr>mid)ret=max(ret,query(rs,mid+1,r,ql,qr));
            return ret;
        }
        #undef ls
        #undef rs
    }xds;
    int whe[N];
    void ins(int c,int id){
        int p=las,np=++seg;
        las=np;tr[np].len=tr[p].len+1;
        while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
        if(!p)tr[np].fail=1;
        else {
            int q=tr[p].son[c];
            if(tr[q].len==tr[p].len+1)tr[np].fail=q;
            else {
                int nq=++seg;
                tr[nq]=tr[q];
                tr[nq].len=tr[p].len+1;
                tr[q].fail=tr[np].fail=nq;
                while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
            }
        }
        whe[id]=las;
    }
    int to[N*2],nxt[N*2],head[N*2],rp;
    void add_edg(int x,int y){
        to[++rp]=y;
        nxt[rp]=head[x];
        head[x]=rp;
    }
    int fa[N*2][21],dep[N*2],dfn[N*2],dfm[N*2],idf[N*2],cnt;
    void dfs(int x){
        dfn[x]=++cnt;idf[cnt]=x;
        fo(i,1,20)fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=head[x];i;i=nxt[i]){
            int y=to[i];
            fa[y][0]=x;dep[y]=dep[x]+1;
            dfs(y);
        }
        dfm[x]=cnt;
    }
    int find(int x,int len){
        if(!x)return 0;
        fu(i,20,0)if(tr[fa[x][i]].len>=len)x=fa[x][i];
        return x;
    }
    int dp[N];
    bool chk(int x){
        int pos1=find(whe[x],dp[x]-1);
        int pos2=find(whe[x-1],dp[x]-1);
        if(pos1&&xds.query(1,1,seg,dfn[pos1],dfm[pos1])>=dp[x]-1)return true;
        if(pos2&&xds.query(1,1,seg,dfn[pos2],dfm[pos2])>=dp[x]-1)return true;
        return false;
    }
    void work(){
        reverse(a+1,a+n+1);
        fo(i,1,n)ins(a[i]-'a',i);
        fo(i,2,seg)add_edg(tr[i].fail,i);
        dfs(1);int cur=0;
        fo(i,1,n){
            dp[i]=dp[i-1]+1;
            while(!chk(i)){
                dp[i]--;cur++;
                xds.ins(1,1,seg,dfn[whe[cur]],dp[cur]);
            }
            ans=max(ans,dp[i]);
        }
        printf("%d",ans);
    }
}sam;
signed main(){
    scanf("%s",a+1);
    n=strlen(a+1);
    sam.work();
    return 0;
}
AC_code(n根号n)
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=5e5+5;
const ull bas=131;
ull hs[N],ba[N];
unordered_map<ull,bool> mp;
int sq,n;
char a[N];
int dp[N],ans;
bool query(int l,int len){
    int r=l+len-1;
    return mp.count(hs[r]-hs[l-1]*ba[len]);
}
signed main(){
    scanf("%s",a+1);
    n=strlen(a+1);ba[0]=1;
    fo(i,1,n)hs[i]=hs[i-1]*bas+a[i]-'a'+1,ba[i]=ba[i-1]*bas;
    mp[0]=1;int len=0;
    fu(i,n,1){
        len++;
        while(!query(i,len-1)&&!query(i+1,len-1)){
            len--;int r=i+len;
            fu(j,dp[r],1){
                if(mp.count(hs[r+j-1]-hs[r-1]*ba[j]))break;
                mp[hs[r+j-1]-hs[r-1]*ba[j]]=1;
            }
        }
        dp[i]=len;
        ans=max(ans,dp[i]);
    }
    printf("%d",ans);
    return 0;
}

T2 虚空恶魔

可以直接在后缀树上维护每个点的\(endpos\)的最小和最大值,直接统计答案

AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=2e6+5;
int n;ll ans;
char a[N];
struct SAM{
    struct POT{
        int len,fail,son[26];
    }tr[N*2];
    int seg,las;
    int mn[N*2],mx[N*2];
    SAM(){
        seg=las=1;
        memset(mn,0x3f,sizeof(mn));
    }
    void ins(int c,int i){
        int p=las,np=++seg;
        las=np;tr[np].len=tr[p].len+1;
        mn[np]=mx[np]=i;
        while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
        if(!p)tr[np].fail=1;
        else {
            int q=tr[p].son[c];
            if(tr[q].len==tr[p].len+1)tr[np].fail=q;
            else {
                int nq=++seg;
                tr[nq]=tr[q];
                tr[nq].len=tr[p].len+1;
                tr[q].fail=tr[np].fail=nq;
                while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
            }
        }
    }
    int buc[N*2],who[N*2];
    void work(){
        fo(i,1,n)ins(a[i]-'a',i);
        fo(i,1,seg)buc[tr[i].len]++;
        fo(i,1,n)buc[i]+=buc[i-1];
        fu(i,seg,1)who[buc[tr[i].len]--]=i;
        fu(i,seg,1){
            int u=who[i],f=tr[u].fail;
            mn[f]=min(mn[f],mn[u]);
            mx[f]=max(mx[f],mx[u]);
            if(mx[u]-mn[u]>=tr[u].len)ans=max(ans,1ll*tr[u].len*max(n-mn[u],mx[u]-tr[u].len));
            else if(mx[u]-mn[u]>tr[f].len)ans=max(ans,1ll*(mx[u]-mn[u])*max(n-mn[u],mn[u]));
        }
        printf("%lld",ans);
    }
}sam;
signed main(){
    // cout<<(sizeof(sam)>>20)<<endl;
    scanf("%s",a+1);
    n=strlen(a+1);
    sam.work();
    return 0;
}

这题码真短!!!

T3 UOJ172

原题把多测删了

同余最短路,这个边数太大,于是过不了,然而我考场上连这个都没有想到(其实是我不会同余最短路)

但是我想到了\(border\)是由\(logn\)个等差数列组成的

然而不会用......

然后搞一堆单调队列啊啥的直接做就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=2e6+5;
int n,m,nxt[N],ans;
char a[N];
int sum[N],num;
int dis[N],ris[N];
int cir[N],c,len;
bool vis[N];
int sta[N],top,bot;
signed main(){
    // cout<<(sizeof(dp)*5>>20)<<endl;
    n=read();m=read();
    scanf("%s",a+1);
    for(int i=2,j=0;i<=n;i++){
        while(j&&a[i]!=a[j+1])j=nxt[j];
        if(a[i]==a[j+1])j++;
        nxt[i]=j;
    }
    int now=n,cha=n;
    sum[++num]=0;
    while(now){
        sum[++num]=n-nxt[now];
        now=nxt[now];
    }memset(dis,0x3f,sizeof(dis));dis[0]=0;
    int lst,v=0,d=0;
    fo(pp,1,num-1){
        lst=v;d=sum[pp+1]-sum[pp];v=sum[pp+1];
        if(pp!=1){
            memcpy(ris,dis,sizeof(dis));memset(dis,0x3f,sizeof(dis));
            fo(i,0,lst-1)if(ris[i]!=inf)dis[ris[i]%v]=min(dis[ris[i]%v],ris[i]);
        }
        memset(vis,false,sizeof(vis));len=2;
        fo(i,0,v-1){
            if(vis[i])continue;
            int beg=i;now=i;
            while((now+lst)%v!=i){
                if(dis[now]<dis[beg])beg=now;
                vis[now]=true;now=(now+lst)%v;
            }vis[now]=true;
            if(dis[now]<dis[beg])beg=now;
            now=beg;c=0;
            while((beg+lst)%v!=now)cir[++c]=beg,beg=(beg+lst)%v;
            cir[++c]=beg;
            top=0;bot=1;
            fo(j,2,c)dis[cir[j]]=min(dis[cir[j]],dis[cir[j-1]]+lst);
        }
        len=0;
        while(sum[pp+1]-sum[pp]==d)pp++,len++;pp--;
        if(len==1)d=0;
        memset(vis,false,sizeof(vis));
        fo(i,0,v-1){
            if(vis[i])continue;
            int beg=i;now=i;
            while((now+d)%v!=i){
                if(dis[now]<dis[beg])beg=now;
                vis[now]=true;now=(now+d)%v;
            }vis[now]=true;
            if(dis[now]<dis[beg])beg=now;
            now=beg;c=0;
            while((beg+d)%v!=now)cir[++c]=beg,beg=(beg+d)%v;
            cir[++c]=beg;
            top=0;bot=1;
            fo(j,1,c){
                while(bot<=top&&j-sta[bot]>=len)bot++;
                if(bot<=top)dis[cir[j]]=min(dis[cir[j]],dis[cir[sta[bot]]]+v+d*(j-sta[bot]));
                while(bot<=top&&dis[cir[sta[top]]]+d*(j-sta[top])>=dis[cir[j]])top--;
                sta[++top]=j;
            }
        }
    }
    fo(i,0,v-1)if(dis[i]<m-n)ans+=(m-n-dis[i])/v+1;
    printf("%lld",ans);
    return 0;
}
posted @ 2021-12-13 20:54  fengwu2005  阅读(46)  评论(0编辑  收藏  举报