NOI模拟21
今天是辽宁OI的省选题,似乎没有那么难,但是T1总感觉在哪里见过,于是就死磕了...
第一题就发现一个性质后就非常简单,否则只能做背包,但是做背包的过程中仍然用到这个性质呵呵
第二题就傻逼dp,7维
第三题考场上用了4分钟连看题加上打出来,拿到了40pts
第四题考场上没有看,但是似乎是构造
T3 盒
组合意义神题,建议看其他人的题解,我不想写式子...
有一个东西要记录一下,从(0,0)走到(n,m)的方案数,一种是直接组合数
另一种是枚举某一行在哪里走到下一行的(可以是任意一行),枚举一下列,然后前面组合数乘上后面组合数就行
通过组合意义的转化可以O(1)去跳,于是均摊就是O(n)的复杂度了
调了好久...
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--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=4e6+5;
const int mod=998244353;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
int T,R=4e6,n,ans,a[N],s[N],w[N];
int jc[N],inv[N];
int C(int x,int y){
if(x<y)return 0;
return jc[x]*inv[y]%mod*inv[x-y]%mod;
}
struct node{
int n,m,i,k,res;
void movi(int x){
while(i<x){
res=(res-C(i+k,i)*C(n-i-1+m-k-1,n-i-1)%mod+mod)%mod;
i++;
}
}
void movk(int x){
while(k<x){
k++;
res=(res+C(i+k-1,k)*C(m-k+n-i-1,m-k))%mod;
}
}
}f1,f2;
signed main(){
T=read();
jc[0]=1;fo(i,1,R)jc[i]=jc[i-1]*i%mod;
inv[0]=1;inv[R]=ksm(jc[R],mod-2);
fu(i,R-1,1)inv[i]=inv[i+1]*(i+1)%mod;
while(T--){
n=read();ans=0;
fo(i,1,n)a[i]=read();
fo(i,1,n-1)w[i]=read();
fo(i,1,n)s[i]=s[i-1]+a[i];
f1=node{n,s[n],0,0,C(s[n]+n-1,s[n]-0)};
f2=node{n+1,s[n]-1,0,0,C(s[n]+n-1,s[n]-1)};
fo(i,1,n-1){
int res=0;
res=(res+i*C(s[n]+n-1,n)%mod-s[i]*C(s[n]+n-1,s[n])%mod+mod)%mod;
// cerr<<res<<" "<<i<<" "<<s[i]<<" "<<i*C(s[n]+n-1,n)%mod-s[i]*C(s[n]+n-1,s[n])%mod<<endl;
if(s[i])f1.movk(s[i]),f1.movi(i),res=(res+2*s[i]*f1.res)%mod;
// cerr<<f1.res<<" ";
if(s[i])f2.movk(s[i]-1),f2.movi(i+1),res=(res-2*i*f2.res%mod+mod)%mod;
// cerr<<f2.res<<" "<<ans<<endl;
ans=(ans+res*w[i])%mod;
}
printf("%lld\n",ans);
}
}
T4 串
构造好题,可以发现下界是\(\frac{n}{2}\),从后面一半开始走,每次向前挪动
发现此时的限制是不能把长度缩成0,于是如果可以找到两个相同的串,那么我们就可以循环跳回去,于是可以长度变成0
那么我们就直接对所有的出现两次以上的串进行统计就好了,最后和下界取max
AC_code
#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--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=5e5+5;
int T,n,ans;char s[N];
int siz[N*2],lft[N*2],buc[N],who[N*2];
struct SAM{
struct POT{
int son[26],fail;
int len;
}tr[N*2];
int seg,las;
SAM(){seg=las=1;}
void clear(){
fo(i,1,seg){
siz[i]=0;lft[i]=0;
fo(j,0,25)tr[i].son[j]=0;
}seg=las=1;
}
void ins(int c){
int np=++seg,p=las;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[np].fail=tr[q].fail=nq;
while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
}
}
}
}sam;
void sol(){
scanf("%s",s+1);n=strlen(s+1);ans=0;sam.clear();
fo(i,1,n)sam.ins(s[i]-'a'),siz[sam.las]=1,lft[sam.las]=i;
fo(i,1,sam.seg)buc[sam.tr[i].len]++;
fo(i,1,n)buc[i]+=buc[i-1];
fo(i,1,sam.seg)who[buc[sam.tr[i].len]--]=i;
fo(i,1,n)buc[i]=0;
fu(i,sam.seg,2){
int x=who[i];
siz[sam.tr[x].fail]+=siz[x];
if(!lft[sam.tr[x].fail]||lft[sam.tr[x].fail]>lft[x])lft[sam.tr[x].fail]=lft[x];
}
fo(i,1,sam.seg)if(siz[i]>1){
// cerr<<lft[i]<<" "<<sam.tr[i].len<<endl;
ans=max(ans,(n-lft[i]>>1)+sam.tr[i].len);
}ans=max(ans,n>>1);
printf("%d\n",ans);
}
signed main(){
T=read();
while(T--)sol();
return 0;
}
QQ:2953174821