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;
}