Codeforces Global Round 14 D. Phoenix and Socks

一、算法分析

如何分析这样的题目?

宏观来看,将两只袜子匹配的花费可能是0,1或2,经过分析,先把0花费匹配完之后,不会影响最终结果。那么我们的目标就是使花费2的尽可能地少。

花费0的匹配为:同色不同左右的匹配。

花费1的匹配为:①同色同左右的匹配;②异色不同左右的匹配。

花费2的匹配为:同色同左右的匹配。

在花费0的匹配结束后,每种颜色的袜子就只剩下左袜子或者右袜子。

设第i种左袜子的个数为l[i],右袜子为r[i].在进行完花费0的操作之后:

不妨设左袜子个数l_cnt>=r_cnt,则优先用l_cnt中r_cnt只袜子去换颜色匹配r_cnt,这样最终答案res+=l_cnt-r_cnt;然后就应该只剩下了左袜子。

接着对于左袜子里,某种颜色i的袜子,假设有k只,若k为偶数则可以用花费1的匹配的①情况,否则还剩下的就是花费2的匹配了.

 

这道题看了好久好久才最后做出来,这启示自己要解出一道题,一定要不断加深对这道题的理解,对题目的理解越深越清晰,则越容易解出来题目。

二、代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdio>
 5 using namespace std;
 6 const int N=200050<<1;
 7 int l[N],r[N];
 8 int n,l_cnt,r_cnt;
 9 inline int read()
10 {
11     bool flag=1;
12     int x=0;
13     char c=getchar();
14     while(c<'0'||c>'9')
15     {
16         if(c=='-')
17             flag=0;
18         c=getchar();
19     }
20     while(c>='0'&&c<='9')
21     {
22         x=(x<<1)+(x<<3)+c-'0';
23         c=getchar();
24     }
25     return (flag?x:~(x-1));
26 }
27 int res;
28 void prework(){
29     memset(l,0,sizeof(l));
30     memset(r,0,sizeof(r));
31     res=0;
32 }
33 void work(int u,int v,int w[]){
34     int len=n;
35     int rest=res;                                         //需要转换形状的左袜子
36     for(int i=1;i<=len;i++){
37         while(rest>0 && w[i]>=2){                         //这样写,比写成if的时间复杂度高,但是代码更好理解,有利于之后复习
38             rest--;
39             w[i]-=2;                                      //组内匹配,故减2                 
40         }
41     }
42     for(int i=1;i<=len;i++){                              //组外匹配(和同左边,不同花色的匹配),对应花费为2的匹配
43         while(rest>0 && w[i]>=1){
44             rest--;
45             w[i]-=1;
46         }
47     }
48     for(int i=1;i<=len;i++)
49         res+=w[i];
50 }
51 int main(){
52     
53     int T;
54     T=read();
55     while(T--){
56         prework();
57         n=read(),l_cnt=read(),r_cnt=read();
58         for(int i=1;i<=l_cnt;i++) l[read()]++;
59         for(int i=1;i<=r_cnt;i++) r[read()]++;
60         l_cnt=r_cnt=0;
61         for(int i=1;i<=n;i++){
62             int minx=min(l[i],r[i]);
63             l[i]-=minx;
64             r[i]-=minx;
65             l_cnt+=l[i];
66             r_cnt+=r[i];
67         }
68         
69         if(l_cnt>=r_cnt) {res+=l_cnt-r_cnt>>1;work(l_cnt,r_cnt,l);}
70         else {res+=r_cnt-l_cnt>>1;work(r_cnt,l_cnt,r);}
71         printf("%d\n",res);
72     }
73     
74     
75     return 0;
76     
77 }

 

posted @ 2021-05-07 09:27  _rhinoceros  阅读(65)  评论(0编辑  收藏  举报