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. 字符串题

构造题真是太神了。。。。

放个题解在这吧。。。。。

image

一点思考,这类题是不是可以列出一个不等式(有取等的情况),然后解得一个关键值(比如这题的\(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. 构造题

什么生成函数啥啥啥的,完全不会,咕了

image

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;
}
posted @ 2022-02-25 12:16  Chen_jr  阅读(28)  评论(0编辑  收藏  举报