NOIP提高組模擬賽15
阿新 • • 發佈:2022-02-25
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;
}