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

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
",ans);
50     }
51     return 0;
52 }
DTOJ4720
原文地址:https://www.cnblogs.com/RenSheYu/p/12313604.html