1. 程式人生 > 其它 >NOIP提高組模擬賽15

NOIP提高組模擬賽15

A. 計數題

以每個位置結尾的字串最多隻有一個,對於一個串,如果擴充套件他的字首,不會使結果變差,那麼我們就強制取以1位置開始的子序列,發現如果產生了衝突,那麼一定是一個字首和一個子串的字尾相同,那麼這個字首或者這個子串我們只能留一個,一個字首可能和多個子串字尾衝突,但是一個子串只會和一個字首衝突,所以我們直接去掉字首,然後發現這其實就是\(n\)減去\(kmp\)求出的\(next\)陣列最大值

code
#include<cstdio>
#include<cstring>

using namespace std;
const int maxn=1000005;
int max(int x,int y){return x>y?x:y;}
char c[maxn];
int net[maxn];
int main(){
    scanf("%s",c+1);
    int n=strlen(c+1);
    int j=0,ans=0;
    for(int i=2;i<=n;++i){
        while(j&&c[j+1]!=c[i])j=net[j];
        if(c[j+1]==c[i])++j;
        net[i]=j;
        ans=max(ans,j);
    }
    printf("%d\n",n-ans);
    return 0;
}

B. 字串題

構造題真是太神了。。。。

放個題解在這吧。。。。。

一點思考,這類題是不是可以列出一個不等式(有取等的情況),然後解得一個關鍵值(比如這題的\(k\)),然後再考慮構造方案?

code
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=500005;

int main(){
    int n;scanf("%d",&n);
    int k=2*n/3-1;
    printf("%d\n",k);
    if(k&1){
        int kn=(k+1)>>1;
        for(int i=1;i<=kn;++i)
          printf("%d %d %d\n",i,k-((i-1)*2),n-i-(k-((i-1)*2)));
        for(int i=kn+1;i<=k;++i)
           printf("%d %d %d\n",i,k-((i-kn)*2-1),n-i-(k-((i-kn)*2-1)));
    }else{
        int kn=k>>1;
        for(int i=1;i<=kn;++i)
         printf("%d %d %d\n",i,k-(i*2-1),n-i-(k-(i*2-1)));
        for (int i=kn+1;i<=k;++i)
         printf("%d %d %d\n",i,k-((i-kn-1)*2),n-i-(k-((i-kn-1)*2)));
    }
    return 0;
}

C. 構造題

什麼生成函式啥啥啥的,完全不會,咕了

code

你以為有程式碼嗎

D. 迴文

題解什麼掃描線完全不知道怎麼用,我隨便口胡了個維護差分的線段樹居然真的能做

首先\(hash+\)二分,可以得出以每個位置為中心的最長迴文,實際上這個迴文半徑就是對答案的貢獻

考慮如果修改一個位置會對當前回文半徑產生的影響,發現這是兩個等差數列\(1,2........r 0 r r-1.....1\)

於是可以用線段樹維護一下,咋維護?差分。然後就變成區間加單點加和區間查,這樣列舉所有迴文中心,可以得到修改某個位置會破壞多少迴文

然後考慮修改,一個有意義的修改,一定是一個迴文兩端外的兩個不同字元,將其中一個改成另外一個

於是可以列舉每個迴文中心,只處理修改對當前回文的貢獻,將兩端修改的貢獻累加一下,\(ans[i][j]\)表示將\(i\)位置修改為\("j"\)字母的貢獻

最後掃一下,減去修改破壞的字元即可

code
#include <cstring>
#include <cstdio>
using namespace std;
long long min(long long x,long long y){return x<y?x:y;}
long long max(long long x,long long y){return x>y?x:y;}
const int maxn=500005,mod=998244353,base=27;
int n,r1[maxn],r2[maxn];
long long ll[maxn],rr[maxn],base_pow[maxn],rem[maxn][29];
char c[maxn];
void per_hash(){
    base_pow[0]=1;c[0]='#';c[n+1]='@';ll[0]=33;rr[n+1]=44;
    for(int i=1;i<=n;++i)base_pow[i]=base_pow[i-1]*base%mod;
    for(int i=1;i<=n;++i)ll[i]=(ll[i-1]*base%mod+c[i]-'a'+1)%mod;
    for(int i=n;i>=1;--i)rr[i]=(rr[i+1]*base%mod+c[i]-'a'+1)%mod;
    ll[n+1]=(ll[n]*base%mod+44)%mod;
    rr[0]=(rr[1]*base%mod+33)%mod;
}
int get_hashl(int l,int r){
    return (ll[r]-ll[l-1]*base_pow[r-l+1]%mod+mod)%mod;
}
int get_hashr(int l,int r){
    return (rr[l]-rr[r+1]*base_pow[r-l+1]%mod+mod)%mod;
}
bool check1(int x,int mid){
    return get_hashl(x+1,x+mid)==get_hashr(x-mid,x-1);
}
bool check2(int x,int mid){
    return get_hashl(x+1,x+mid)==get_hashr(x-mid+1,x);
}
bool check3(int x,int r,int ll,int rr){
    return get_hashl(rr+1,x+r)==get_hashr(x-r,ll-1);
}
bool check4(int x,int r,int ll,int rr){
    return get_hashl(rr+1,x+r)==get_hashr(x-r+1,ll-1);
}
struct tree{
    struct node{
        long long sum,lazy;
    };
    node t[maxn<<4|1];
    void push_down(int x,int l,int r){
        int ls=(x<<1),rs=(x<<1|1),mid=(l+r)>>1;
        t[ls].lazy+=t[x].lazy;
        t[rs].lazy+=t[x].lazy;
        t[ls].sum+=t[x].lazy*(mid-l+1);
        t[rs].sum+=t[x].lazy*(r-mid);
        t[x].lazy=0;
    }
    void modify(int x,int l,int r,int L,int R,long long z){
        if(L<=l&&r<=R){
            t[x].lazy+=z;
            t[x].sum+=(r-l+1)*z;
            return;
        }
        if(t[x].lazy)push_down(x,l,r);
        int mid=(l+r)>>1;
        if(L<=mid)modify(x<<1,l,mid,L,R,z);
        if(R>mid)modify(x<<1|1,mid+1,r,L,R,z);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    long long  query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R)return t[x].sum;
        if(t[x].lazy)push_down(x,l,r);
        int mid=(l+r)>>1;
        long long ans=0;
        if(L<=mid)ans+=query(x<<1,l,mid,L,R);
        if(R>mid)ans+=query(x<<1|1,mid+1,r,L,R);
        return ans;
    }
    void add_dz(int l,int r){
        modify(1,1,n,l,r,1);
        modify(1,1,n,r+1,r+1,-(r-l+1));
    }
    void add_dj(int l,int r){
        modify(1,1,n,l,l,(r-l+1));
        modify(1,1,n,l+1,r+1,-1);
    }
    long long ask(int pos){
        return query(1,1,n,1,pos);
    }
}T;
int mr1(int x,int l,int r){
    while(l<r){
        if(r-l<=2){
            for(int i=r;i>l;--i)
            if(check1(x,i))return i;
            return l;
        }
        int mid=(l+r)>>1;
        if(check1(x,mid))l=mid;
        else r=mid-1;
    }
    return l;
}
int mr2(int x,int l,int r){
    while(l<r){
        if(r-l<=2){
            for(int i=r;i>l;--i)
            if(check2(x,i))return i;
            return l;
        }
        int mid=(l+r)>>1;
        if(check2(x,mid))l=mid;
        else r=mid-1;
    }
    return l;
}
void get_dt1(int x){
    int ll=x-r1[x]-1,rr=x+r1[x]+1;
    if(!ll||rr>n)return;
    int l=r1[x]+2,r=min(x-1,n-x)+1,ans=r1[x]+2;
    while(l<r){
        if(l>r)break;
        if(r-l<=2){
            for(int i=l;i<=r;++i)
            if(!check3(x,i,ll,rr)){ans=i;break;}
            break;
        }
        int mid=(l+r)>>1;
        if(check3(x,mid,ll,rr))l=mid+1;
        else r=mid;
    }
    int dt=ans-r1[x]-1;
    rem[ll][c[rr]-'a'+1]+=dt;
    rem[rr][c[ll]-'a'+1]+=dt;
}
void get_dt2(int x){
    int ll=x-r2[x],rr=x+r2[x]+1;
    if(!ll||rr>n)return;
    int l=r2[x]+2,r=min(x,n-x)+1,ans=r2[x]+2;
    while(l<r){
        if(l>r)break;
        if(r-l<=2){
            for(int i=l;i<=r;++i)
            if(!check4(x,i,ll,rr)){ans=i;break;}
            break;
        }
        int mid=(l+r)>>1;
        if(check4(x,mid,ll,rr))l=mid+1;
        else r=mid;
    }
    int dt=ans-1-r2[x];
    rem[ll][c[rr]-'a'+1]+=dt;
    rem[rr][c[ll]-'a'+1]+=dt;
}
int main(){
    scanf("%s",c+1);
    n=strlen(c+1);
    per_hash();
    for(int i=1;i<=n;++i){
        r1[i]=mr1(i,0,min(i-1,n-i));
        if(r1[i])T.add_dj(i+1,i+r1[i]),T.add_dz(i-r1[i],i-1);
        if(i==n)break;
        r2[i]=mr2(i,0,min(i,n-i+1));
        if(r2[i])T.add_dj(i+1,i+r2[i]),T.add_dz(i-r2[i]+1,i);
    }
    for(int i=1;i<=n;++i)get_dt1(i);
    for(int i=1;i<n;++i)get_dt2(i);
    long long ans=0;
    for(int i=1;i<=n;++i){
        long long ls=T.ask(i);
        long long ks=0;
        for(int j=1;j<=26;++j)ks=max(ks,rem[i][j]-ls);
        ans=max(ans,ks);
    }
    for(int i=1;i<=n;++i)ans+=r1[i];
    for(int i=1;i<n;++i)ans+=r2[i];
    printf("%lld\n",ans+n);
    return 0;
}