2020 省选模拟测试 Round #11 solution (20/02/15)
【比赛链接】http://59.61.75.5:8018/contest/221
A. 怪兽
【题解】
首先显然有回合越少越优. 二分求出最少需要的回合.
分类讨论:
①先杀 A 后杀 B:
二分杀 A 需要的回合,若剩下的杀不了 B 则将 A 中多余的一回合删去. 可以证明,A 中一定可以删去一回合使得刚好杀掉 A.
②先杀 B 后杀 A:
最优显然构造 AAABBBAAA 的情况.
逐位贪心,考虑后面能否杀完即可. 优先选 A. 具体细节参见代码.
【代码】
1 #include<bits/stdc++.h> 2 inline int read ( void ) 3 { 4 int x=0;char ch; 5 while ( !isdigit(ch=getchar()) ) ; 6 for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48); 7 return x; 8 } 9 const int maxn=100000+10; 10 long long sum[maxn]; 11 char ans[3][maxn]; 12 inline void Print ( int k,int T,long long res ) 13 { 14 printf("%lld ",res); 15 for ( int i=1;i<=T;i++ ) putchar(ans[k][i]); 16 puts(""); 17 } 18 signed main() 19 { 20 for ( int i=1;i<=100003;i++ ) sum[i]=sum[i-1]+i; 21 for ( int Cases=read();Cases--; ) 22 { 23 long long ha=read(),hb=read(),atka=read(),atkb=read(); 24 long long T=std::lower_bound(sum+1,sum+100004,ha+hb)-sum; 25 26 long long A=std::lower_bound(sum+1,sum+100004,ha)-sum; 27 long long vala=A*atka+T*atkb; 28 for ( long long i=1;i<=A;i++ ) ans[1][i]='A'; 29 for ( long long i=A+1;i<=T;i++ ) ans[1][i]='B'; 30 if ( sum[T]-sum[A]<hb ) ans[1][sum[A]-ha]='B'; 31 32 long long B=std::lower_bound(sum+1,sum+100004,hb)-sum; 33 long long p=std::upper_bound(sum+1,sum+100004,sum[B]-hb)-sum-1; 34 long long valb=T*atka+B*atkb; 35 for ( long long i=1;i<=p;i++ ) ans[2][i]='A'; 36 for ( long long i=p+1;i<=B;i++ ) ans[2][i]='B'; 37 for ( long long i=B+1;i<=T;i++ ) ans[2][i]='A'; 38 if ( sum[T]-sum[B]+sum[p]<ha ) 39 { 40 long long res=ha-sum[T]+sum[B]; 41 for ( long long i=1;i<=B;i++ ) 42 if ( res>2*i or res==i ) res-=i,ans[2][i]='A'; 43 else ans[2][i]='B'; 44 } 45 46 if ( vala<valb ) Print(1,T,vala); 47 else if ( vala>valb ) Print(2,T,valb); 48 else 49 { 50 int f=1; 51 for ( int i=1;i<=T;i++ ) 52 if ( ans[1][i]<ans[2][i] ) break; 53 else if ( ans[1][i]>ans[2][i] ) { f=2;break; } 54 Print(f,T,vala); 55 } 56 } 57 return 0; 58 }
B. 区间
【题解】
考虑转化为字符串求解. 考虑本质不同的子串,建出 SAM,则每个节点的 $right$ 大小即为这个节点的贡献.
用单调栈维护编号,extend 时二分查找 $right$ 大小对应的编号位置,计算即可.
【代码】
1 #include<bits/stdc++.h> 2 inline int read ( void ) 3 { 4 int x=0;char ch; 5 while ( !isdigit(ch=getchar()) ) ; 6 for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48); 7 return x; 8 } 9 const int maxn=400000+10; 10 int size=1,root=1,last=1,val[maxn],len[maxn],fa[maxn],st[maxn],a[maxn],tp; 11 std::unordered_map<int,int> ch[maxn];long long sum[maxn],ans; 12 inline void extend ( int c ) 13 { 14 int np=++size,p=last;val[np]=1;len[np]=len[p]+1;last=np; 15 while ( p and !ch[p].count(c) ) ch[p][c]=np,p=fa[p]; 16 if ( !p ) fa[np]=root; 17 else 18 { 19 int q=ch[p][c]; 20 if ( len[q]==len[p]+1 ) fa[np]=q; 21 else 22 { 23 int nq=++size;len[nq]=len[p]+1;fa[nq]=fa[q]; 24 fa[q]=fa[np]=nq;ch[nq]=ch[q]; 25 while ( p and ch[p][c]==q ) ch[p][c]=nq,p=fa[p]; 26 } 27 } 28 int L=len[np]-len[fa[np]]; 29 int pos=std::lower_bound(st+1,st+tp+1,L)-st; 30 ans+=sum[pos-1]+1LL*a[st[pos]]*(L-st[pos-1]); 31 } 32 inline void C ( void ) 33 { 34 for ( int i=1;i<=size;i++ ) ch[i].clear(),fa[i]=0; 35 root=last=size=1;tp=0;ans=0; 36 } 37 signed main() 38 { 39 for ( int T=read();T--;C() ) 40 { 41 int n=read(); 42 for ( int i=1;i<=n;i++ ) 43 { 44 a[i]=read(); 45 while ( tp and a[st[tp]]<=a[i] ) tp--; 46 st[++tp]=i;sum[tp]=sum[tp-1]+1LL*a[i]*(st[tp]-st[tp-1]); 47 extend(a[i]); 48 } 49 printf("%lld\n",ans); 50 } 51 return 0; 52 }