hhhh感觉我真的太久没有接触过OI了

大约是前天听到JK他们约着一起刷codeforces,假期里觉得有些颓废的我忽然也心血来潮来看看题目

今天看codeforces才知道居然有div3了,感觉应该看名字比div2还要简单吧,于是我就做了做....发现确实还蛮简单的hhhh

但是我又突发奇想,干脆更新一篇博客吧,毕竟这也是我少有的能刷完一整套CF的题,那也可以记录一下啦...(虽然div3的题解似乎拿来充当一个题解还是有点水的hhhh)

A - Two distinct points

题目大意:n组数据,每次给你[l1,r1]和[l2,r2]让你输出两个不同的元素a,b,使得a在[l1,r1]中,b在[l2,r2]中,题目保证一定有解

这两个数的限制实在是....没什么限制hhhh,第一眼看到居然感觉不知道怎么下手。

然后就想了一下,那要不选个a就不在[l2,r2]里面,然后b就可以随便选,发现这样的话就要比一下什么区间谁在前谁在后,或者谁包含谁什么的,实在有点麻烦。

后面想了一下,唔那我a就选个端点吧,感觉它容易不在[l2,r2]里面一些,那再想一下,那我b也选端点吧

于是那就a=l1或r1,b=l2或r2,然后要求a!=b,这就实在太水了hhhh 果然是div3,不过既然这是一篇题解,我就水到底吧:

所以我们判断一下l1是不是等于l2

  如果不相等,那就a=l1,b=l2;

  如果相等的话,我就比一下l1是不是等于r2

    如果不等就a=l1,b=r2,;

    如果相等,说明l1==l2==r2,那么b就一定要等于l2,题目又保证有解,那就有r1!=l2,那么a=r1,b=l2就好了。

 

 1 #include<cstdio>
 2 
 3 using namespace std;
 4 
 5 int main(){
 6     int Kase,l1,r1,l2,r2;
 7     scanf("%d",&Kase);
 8     while(Kase--){
 9         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
10         if(l1!=l2)
11             printf("%d %d\n",l1,l2);
12         else if(l1!=r2)
13             printf("%d %d\n",l1,r2);
14         else
15             printf("%d %d\n",r1,l2);
16     }
17     return 0;
18 }
View Code

然后交上去,刷新,1A!哇好开心啊! [虽然不知道这种题过了有什么好开心的Hhhhh,可能是codeforce的题确实会给你一种实现超简单,但是想法是自己独创的这种很棒的成就感吧]

不过也就对B题也充满了信心。

B. Divisors of Two Integers

题目大意:这题大概就是先告诉你一种获得集合的方法:给你x和y,然后把他们的因子分别放到集合A,B中去,最后把A,B直接融合在一起,变成一个大的可重复元素的集合C。题目给你这个集合C,让你求出x和y的确切值。集合大小<200,元素大小<10000

刚开始感觉这大约是一个数学题,可能需要分解因式什么的,或者是什么通过最大公约数来反推两个元素的值的题。

然后忽然发现,好像它是所有的因子都在里面hhh,也就是包括了x和y自己,所以我只需要通过找最大值肯定就能找到x和y中的一个,不妨令x是那个最大的。

那么我现在的任务就是把x的因子从集合C中拿走,然后剩下的就是集合B了,那么剩下的里面最大的就是元素y了。

当然你没有必要真的把x的所有因子从集合中拿走,你只需要判断一下集合中的某个元素能否被x整除就行了,然后剩下的不能整除的最大的就是y。

上面是y不是x的因子的情况,如果y是x的因子,那么你就需要找到一个最大的出现了两次的元素,因为元素大小<10000所以可以用桶来实现,如果元素大小大到不能用桶的话,就可以用排序来实现。

 1 #include<cstdio>
 2 
 3 const int maxn=210;
 4 
 5 int n;
 6 int a[maxn],cnt[10010];
 7 int x,y,z;
 8 
 9 int main(){
10 #ifndef ONLINE_JUDGE
11     freopen("x.in","r",stdin);
12 #endif
13 
14     scanf("%d",&n);
15     for(int i=1;i<=n;i++){
16         scanf("%d",&a[i]);
17         x=x>a[i]?x:a[i]; 
18     }
19     for(int i=1;i<=n;i++){
20         if(x%a[i])
21             y=y>a[i]?y:a[i];
22         else if(++cnt[a[i]]>=2)
23             z=z>a[i]?z:a[i];
24     }
25     y=(y==0)?z:y;
26     printf("%d %d",x,y);
27 
28     return 0;
29 }
View Code

 

然后又是1A,哇太感动了,简直神清气爽,于是对C题也充满了自信。

C. Nice Garland

题目大意:给你一个只包含RGB三种字符的字符串,希望你把它改造成它想要的样子,它想要的样子就是相同颜色的元素之间的距离为3的倍数。字符串大小为200000,需要输出一个改造最少的次数以及改造后的字符串。

刚开始看到改造字符串这种题,就感觉是个DP,然后研究了一下样例,发现好像样例输出都是类似RGBRGBRG...或者BRGBRGBRG...唔,然后发现好像它这个要求相同颜色的元素之间的距离都为3的倍数的要求确实十分苛刻了。

例如第一个元素你放上了R,那么你考虑它后面的三个元素R _ _ _,如果第三个位置上不放R,那么只能放G或者B,不妨假设放了G

R _ _ G 那么你会发现第二个空位只能放B,因为如果放R或者G都会让距离不满足3的倍数的条件,于是就变成了R B _ G 然后第三个空位上就什么也放不了了。

所以如果第一个元素是R,那么第四个元素就必须也是R,所以就只有6种全排列的扩展串或者扩展串的子串了,于是就只需要比较6次取最小的就好了。

 1 /*
 2   File : C.cpp
 3   Author : Robert_Yuan
 4   Date : 2019/1/29
 5   Discription :
 6 */
 7 #include<cstdio>
 8 #include<cstring>
 9 
10 using namespace std;
11 
12 const int maxn=200010;
13 
14 int n,ans,ansi;
15 char ch[maxn];
16 char s[6][4]={"RGB","RBG","GRB","GBR","BRG","BGR"};
17 
18 int main(){
19 #ifndef ONLINE_JUDGE
20     freopen("x.in","r",stdin);
21 #endif
22 
23     scanf("%d%s",&n,ch);
24     ans=n;
25     for(int i=0;i<6;i++){
26         int cnt=0;
27         for(int j=0;j<n;j+=3){
28             cnt+=(ch[j]!=s[i][0])&(j<n);
29             cnt+=(ch[j+1]!=s[i][1])&(j+1<n);
30             cnt+=(ch[j+2]!=s[i][2])&(j+2<n); 
31         }
32         if(cnt<ans)
33             ans=cnt,ansi=i;
34     }
35     printf("%d\n",ans);
36     for(int i=0;i<n;i+=3){
37         if(i<n) printf("%c",s[ansi][0]);
38         if(i+1<n) printf("%c",s[ansi][1]);
39         if(i+2<n) printf("%c",s[ansi][2]);
40     }
41 
42     return 0;
43 }
View Code

 

这题我maxn打错了RE了一次,于是开始慢慢谨慎起来Hhh,接着是D题

D. Diverse Garland

题目大意:还是一个只包含RGB三种字符的字符串,希望你把它改造成相邻的两个元素不相等的样子,问你最少需要改造多少次,然后输出改造后的字符串。字符串长度<200000.

这个就很经典了,就是上面想到的DP了,f[i][j]表示第i个元素修改成j的代价,其中j只能取0,1,2

然后转移方程大概就是每次从前一个是那种颜色转移过来,如果枚举的颜色和当前的不一样就要+1,一样的话就不用加

f[i][0]=Min(f[i-1][1],f[i-1][2])+(ch[i]!='R'); [其他两个也类似]

然后用一个pre[i][j]记录一下当前状态从i-1的哪一个状态转移过来,就可以输出改造后的字符串了。

 1 /*
 2   File :
 3   Author : Robert_Yuan
 4   Date : 2019/1/29
 5   Discription :
 6 */
 7 #include<cstdio>
 8 #include<cstring>
 9 
10 using namespace std;
11 
12 const int maxn=200010;
13 
14 int n;
15 int f[maxn][3],pre[maxn][3];
16 char ch[maxn];
17 char Turn[3]={'G','R','B'};
18 
19 int main(){
20 #ifndef ONLINE_JUDGE
21     freopen("x.in","r",stdin);
22 #endif
23 
24     scanf("%d%s",&n,ch);
25     memset(f,0x3f,sizeof(f));
26     for(int i=0;i<3;i++)
27         f[0][i]=(ch[0]!=Turn[i]);
28     for(int i=1;i<n;i++)
29         for(int j=0;j<3;j++)
30             for(int k=0;k<3;k++)
31                 if(j!=k){
32                     int val=f[i-1][k]+(ch[i]!=Turn[j]);
33                     if(f[i][j]>val)
34                         f[i][j]=val,pre[i][j]=k;
35                 }
36     int ans=0x3f3f3f3f,ansi;
37     for(int i=0;i<3;i++){
38         if(ans>f[n-1][i])
39             ans=f[n-1][i],ansi=i;
40     }
41     for(int i=n-1;i>=0;i--){
42         ch[i]=Turn[ansi];
43         ansi=pre[i][ansi];
44     }
45     printf("%d\n",ans);
46     printf("%s",ch);
47     return 0;
48 } 
View Code

相关文章: