cf round #421 div2 C. Mister B and Boring Game(trick)

链接:http://codeforces.com/contest/820/problem/C

分析:A完一觉起来发现数据改了,WA掉了。。出题人觉得自己做法错了。。

首先把字符串记为A1 B1 A2 B2 A3 B3……,事实上,A3与A1完全一样,因此是个周期数列。为了方便,把a记做1,b记做2,以此类推。对于B来说,最优策略是选择与最后a-b个字母其中一个一样的,然后a>=b时,A2就会变成1,2,...,b,1+a,...,2a-b,

a<b时,就是1到a+1,跳过选择的那个字母。

周期性证明:按前面的取法,a>b时,A2中[b+1,a]这一段不能取,a<=b时,a不能取,因此A2为从a开始跳过不能取的一段,记A2=A21+A22,A3恰好只需和A22互异,所以可以从1取到a,形成周期,T=2(a+b)。

由周期性证明易得,在一个周期内,记互异元素个数为t,若a>=b,t=2a-b,否则t=a+1。

当r-l>=T时,由周期性知,答案为t,否则,对T取余,转化为一个周期内的问题,枚举选择的字母,求一下区间内的最小值即可。

B1、B2必然选择同一个字母。首先,只要满足贪心,是否选同一字母不影响周期性。考虑mod完的r和l,假设选择不同字母,先考虑l<=r,若r在B2,显然选择不同字母不会更优;若r在B2之前,B2取什么并不影响。如果l>r,即答案为[1,r]加上[l,a+b]的互异元素个数,

同样,选择不同字母并不会更优,因此枚举时只需要枚举同一个即可。

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 typedef long long ll;
 5 ll a,b,l,r,ans=100,T;
 6 ll Cal(char c){
 7     ll count=0;
 8     char s[100];
 9     for(int i=0;i<a;i++)
10         s[i]='a'+i;
11     for(int i=a;i<a+b;i++)
12         s[i]=c;
13     int have[26];
14     memset(have,0,26*sizeof(int));
15     for(ll i=a+b-1;i>=b;i--){
16         have[s[i]-'a']=1;
17     }
18     ll i=a+b,j=0;
19     while(i<2*a+b){
20         while(have[j]){
21             j++;
22         }
23         s[i]=j+'a';
24         i++;j++;
25     }
26     for(int i=2*a+b;i<T;i++)
27         s[i]=s[i-1];
28     memset(have,0,26*sizeof(int));
29     if(l<=r){
30         for(ll i=l;i<=r;i++){
31             if(!have[s[i]-'a']){
32                 count++;have[s[i]-'a']=1;
33             }
34         }
35     }else{
36         for(ll i=0;i<=r;i++){
37             if(!have[s[i]-'a']){
38                 count++;have[s[i]-'a']=1;
39             }
40         }
41         for(ll i=l;i<T;i++){
42             if(!have[s[i]-'a']){
43                 count++;have[s[i]-'a']=1;
44             }
45         }
46     }
47     return count;
48 }
49 int main(){
50     ll t;
51     cin>>a>>b>>l>>r;
52     l--;r--;
53     T=2*(a+b);
54     if(a>b+1)t=2*a-b;
55     else t=a+1;
56     if(r-l>=T)ans=t;
57     else{
58         r%=T;l%=T;
59         for(int i=0;i<a;i++){
60             ans=min(Cal('a'+i),ans);
61         }
62     }
63     cout<<ans<<endl;
64     return 0;
65 }
原文地址:https://www.cnblogs.com/7391-KID/p/7088904.html