[考试反思]0415省选模拟71:限制
奇奇怪怪的一场考试。状态还是有点差。
一看$T2$这$30000$的数据范围就知道大概可以$n^2$卡过。
然后纠结了半天到底要想正解还是卡暴力。于是又花了好长时间想正解然而什么都没想出来。
于是就开始卡暴力,的确卡的挺快的但是细节挂了一处丢了$40pts$。
在靠后也是除了牛逼以外跑得最快的。然而并没有什么用,$WA$了就没啥好说的。
结果犹犹豫豫磨磨叽叽等$T2$弄完时间也就不多了。于是$T1/3$只好定位为暴力。
过程中$T1$的正解在脑中一闪而过然而并没有花时间继续想(也没那个时间了)
最后$T1$的暴力不明原因$50$挂成$40$。$T3$的$15pts$暴力莫名其妙拿到了$30pts$
就这样了。就是仨题炸了俩。暴力写的倒是挺全。时间分配炸掉了。
T1:王子
大意:$n$点序列,每个点有$A_i,B_i$两种权值,要求每个点选择一种权值满足任意连续$k$个点中至少$P$个$A$权值至少$Q$个$B$权值。最大化权值和。$n \le 200$
数据范围闻上去像网络流的味道。
每个节点代表一个长为$k$的区间然后把这些点串起来,原图里的每个点作为一条边驾在它所对应的最左/右的区间之间。
无源汇上下界最大费用可行流。带正环,所以只要像你钦定下界一样钦定正边满流,调整度数并建反边就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 5555 4 int n,k,A,B,ans,T,fir[S],l[S],to[S],d[S],v[S],w[S],ec=1,q[S],iq[S],al[S]; 5 void link(int a,int b,int V,int W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;} 6 void con(int a,int b,int V,int W=0){ 7 if(W<=0)link(a,b,V,W),link(b,a,0,-W); 8 else link(a,b,0,W),link(b,a,V,-W),ans+=W,d[a]++,d[b]--; 9 } 10 bool bfs(){ 11 for(int i=1;i<=T;++i)d[i]=-998244353; 12 for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(d[to[i]]<d[q[h]]+w[i]&&v[i]){ 13 d[to[i]]=d[q[h]]+w[i]; 14 if(!iq[to[i]])q[++t]=to[i]; 15 }return d[T]!=-998244353; 16 } 17 int dfs(int p,int f){int r=f; 18 if(p==T)return f; al[p]=1; 19 for(int i=fir[p];i&&r;i=l[i])if(!al[to[i]]&&d[to[i]]==d[p]+w[i]&&v[i]){ 20 int x=dfs(to[i],min(r,v[i])); 21 if(!x)d[to[i]]=-998244353; 22 ans+=w[i]*x; v[i]-=x; v[i^1]+=x; r-=x; 23 }al[p]=0;return f-r; 24 } 25 int main(){ 26 cin>>n>>k>>A>>B; T=n-k+3; d[1]=B; d[T-1]=-B; 27 for(int i=1,x,e;i<=n;++i)scanf("%d%d",&x,&e),ans+=x,con(min(n-k+2,i+1),max(1,i-k+1),1,e-x); 28 for(int i=1;i<T-1;++i)con(i,i+1,k-A-B); 29 for(int i=1;i<T;++i)if(d[i]<0)con(0,i,-d[i]);else con(i,T,d[i]); 30 while(bfs())dfs(0,n); 31 cout<<ans<<endl; 32 }
T2:遇见
大意:求满足(出现过的数出现次数都是奇数)的子区间个数。$n \le 30000$
暴力卡常直接过。
我加剪枝了:如果这个数目前出现了偶数次且没有下一次出现则直接跳过。
然后我还把连续的同一种数压在了一起。就过去了。
正解的话,随机化,给每种颜色随机一个权值然后问题就是求异或和为$0$的区间个数。
枚举右端点,考虑权值变化。并不会修改,分块+$trie$就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[33333],n,N,Ans;bool nxt[33333];short lst[1000005],cnt[1000005],t[33333]; 4 int main(){ 5 scanf("%d",&n); 6 for(int i=1;i<=n;++i){ 7 N++; 8 scanf("%d",&a[N]); 9 if(a[N]==a[N-1])N--; 10 else nxt[lst[a[N]]]=1,lst[a[N]]=N; 11 t[N]++; 12 } 13 for(int i=1;i<=N;++i){ 14 register int R=N,z=0,ans=0; 15 for(int j=i;j<=R;++j){ 16 if(z==0)ans+=cnt[a[j]]?t[j]>>1:t[j]+1>>1; 17 else if(z==1&&cnt[a[j]]&&(cnt[a[j]]&1)==0)ans+=t[j]+1>>1; 18 z-=cnt[a[j]]&&(cnt[a[j]]&1)==0; 19 cnt[a[j]]+=t[j]; 20 z+=(cnt[a[j]]&1)==0; 21 if(!nxt[j]&&(cnt[a[j]]&1)==0)R=j; 22 }for(int j=i;j<=R;++j)cnt[a[j]]-=t[j]; 23 for(int j=t[i]&1?1:2;j<=t[i];j+=2)Ans+=ans,ans--; 24 if(t[i]==1)continue; 25 t[i]--;ans=z=0;R=N; 26 for(int j=i;j<=R;++j){ 27 if(z==0)ans+=cnt[a[j]]?t[j]>>1:t[j]+1>>1; 28 else if(z==1&&cnt[a[j]]&&(cnt[a[j]]&1)==0)ans+=t[j]+1>>1; 29 z-=cnt[a[j]]&&(cnt[a[j]]&1)==0; 30 cnt[a[j]]+=t[j]; 31 z+=(cnt[a[j]]&1)==0; 32 if(!nxt[j]&&(cnt[a[j]]&1)==0)R=j; 33 }for(int j=i;j<=R;++j)cnt[a[j]]-=t[j]; 34 for(int j=t[i]&1?1:2;j<=t[i];j+=2)Ans+=ans,ans--; 35 }cout<<Ans<<endl; 36 }
T3:字符串
大意:给出$n$个模式串满足其$trie$节点$\le 50$,给定匹配串支持以下操作:
询问子区间$[l,r]$中模式串出现次数和。将子区间$[l,r]$循环赋值为$str$(就是把$str$复制若干遍覆盖$[l,r]$)$|S|,Q,\sum |str| \le 10^5$
题目提示的已经很明显了是$AC$自动机。
区间修改能想到的就是线段树。
我们对线段树每个节点维护$t[i]$表示在线段树左端点进入之前匹配到$AC$自动机的节点$i$的话那么加入区间的字符串之后会匹配到$t[i]$。
并且维护$w[i]$表示过程中出现的模式串个数。
可以拿到没有修改的部分分以及可以暴力修改的部分分。
然后我们对于每个$str$维护一个$g[a][b][c][d]$表示对于第$a$个修改操作对应的$str$从其第$b$位开始走$2^c$位,最开始从$AC$自动机$d$结点出发最后到了哪里以及贡献
就可以倍增了。
为了方便我们把线段树最开始的大小重置为$2$的整次幂,那么这个倍增数据就可以直接得到一个节点的值。
时间复杂度大约是$O(Qlog\ n |S|)$这级别的。
时空都要注意,千万别$vector$。$g$的$a,b$可以压成一维就不用$vector$了。我蠢的一批还写了个内存池。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 1<<20 4 int fail[55],c[55][27],q[55],n,Q,v[55],W[55],pc,rt,mi[S]; char s[S]; 5 int lz[S],w[S][51],t[S][51],len,lp,ans,lend[S],cnt,lenth[S],bit,pool[1<<28],SIZE; 6 void insert(int&p,int l){ 7 if(!p)p=++pc; 8 if(!s[l]){v[p]++;return;} 9 insert(c[p][s[l]-'a'],l+1); 10 } 11 struct ST{ 12 int bgv,bge,st1,st2; 13 int&v(int a,int b,int c){return pool[bgv+a*st1+b*st2+c];} 14 int&e(int a,int b,int c){return pool[bge+a*st1+b*st2+c];} 15 void init(){ 16 int l=lenth[++cnt]=strlen(s); 17 st2=l; st1=l*(pc+1); bgv=SIZE; SIZE+=st1*(bit+1); bge=SIZE; SIZE+=st1*(bit+1); 18 for(int j=0;j<l;++j)for(int i=1;i<=pc;++i) 19 v(0,i,j)=c[i][s[j]-'a'],e(0,i,j)=W[v(0,i,j)]; 20 for(int i=1;i<=bit;++i)for(int j=0;j<l;++j)for(int k=1;k<=pc;++k) 21 v(i,k,j)=v(i-1,v(i-1,k,j),(j+(1<<i-1))%l), 22 e(i,k,j)=e(i-1,v(i-1,k,j),(j+(1<<i-1))%l)+e(i-1,k,j); 23 } 24 }R;vector<ST>st; 25 #define lc p<<1 26 #define rc lc|1 27 #define md (L+R>>1) 28 void up(int p){for(int i=1;i<=pc;++i)t[p][i]=t[rc][t[lc][i]],w[p][i]=w[lc][i]+w[rc][t[lc][i]];} 29 void build(int p,int L,int R){ 30 if(L==R){ 31 if(R<=len)for(int i=1;i<=pc;++i)t[p][i]=c[i][s[L]-'a'],w[p][i]=W[c[i][s[L]-'a']]; 32 return; 33 }build(lc,L,md);build(rc,md+1,R); up(p); 34 } 35 void cov(int p,int L,int R,int o){ 36 int B=mi[R-L+1],z=(L-lend[o])%lenth[o]; lz[p]=o; 37 for(int i=1;i<=pc;++i)t[p][i]=st[o].v(B,i,z),w[p][i]=st[o].e(B,i,z); 38 } 39 void down(int p,int L,int R){cov(lc,L,md,lz[p]);cov(rc,md+1,R,lz[p]);lz[p]=0;} 40 void ask(int l,int r,int p=1,int L=1,int R=n){ 41 if(l<=L&&R<=r){ans+=w[p][lp];lp=t[p][lp];return;} 42 if(lz[p])down(p,L,R); 43 if(l<=md)ask(l,r,lc,L,md); if(r>md)ask(l,r,rc,md+1,R); 44 } 45 void mdf(int l,int r,int p=1,int L=1,int R=n){ 46 if(l<=L&&R<=r){cov(p,L,R,cnt); return;} 47 if(lz[p])down(p,L,R); 48 if(l<=md)mdf(l,r,lc,L,md); if(r>md)mdf(l,r,rc,md+1,R); up(p); 49 } 50 int main(){//freopen("ex_string2.in","r",stdin);freopen("0.out","w",stdout); 51 for(int i=0;i<=19;++i)mi[1<<i]=i; 52 cin>>n>>Q; st.push_back(R); 53 for(int i=1;i<=n;++i)cin>>s,insert(rt,0); 54 q[1]=1; fail[0]=1; 55 for(int i=0;i<26;++i)c[0][i]=1; 56 for(int h=1,t=1;h<=t;++h)for(int j=0;j<26;++j) 57 if(c[q[h]][j])fail[q[++t]=c[q[h]][j]]=c[fail[q[h]]][j]; 58 else c[q[h]][j]=c[fail[q[h]]][j]; 59 for(int i=1;i<=pc;++i)for(int j=i;j;j=fail[j])W[i]+=v[j]; 60 scanf("%s",s+1); len=strlen(s+1);n=1; 61 while(n<len)n<<=1,bit++; build(1,1,n); 62 while(Q--){ 63 int op,x,y;scanf("%d%d%d",&op,&x,&y); 64 if(op==2)lp=1,ans=0,ask(x,y),printf("%d\n",ans); 65 else scanf("%s",s),R.init(),st.push_back(R),mdf(lend[cnt]=x,y); 66 } 67 }