zoukankan      html  css  js  c++  java
  • CF1251 的题解

    CF1251 的题解

     

             没有错,本小菜鸡又腆着个波脸来写题解了,菜还理直气壮。

    A题

            

             题面:说有一个键盘坏了,然后坏掉的键按一次会出现两个相应的字母,好的键是按一次只会出现一个相应的字母。

      做法:需要判断一个字母连续出现的次数,如果为奇数那么说明这个键是好的。

      水题,没错我又觉得这是水题了

    B题

             题面:给出n个01字符串,然后意思是可以任意交换01的位置,哪怕不是一个字符串的也可以交换。问最多可以转化出多少个回文串。

             做法:首先我们可以想到对于长度为奇数的01字符串来说,他必是一个回文串(您要是能举出反例,我就是粪海狂蛆)。 对于长度为偶数的01字符串来说,如果不是回文串那么说明此时01的个数都是奇数。我们只需要任意换掉一个0或者1就可组成一个回文串了。

            

             我们数出不是回文串的01串的个数尽心两两配对(一个拿1一个拿0)。

    如果个数为偶数那么就是最好的情况,答案就是n;如果为奇数,我们就需要考虑有没有长度为奇数的01串,我们和中间那个位置的字符交换,就可以凑成回文串(举个栗子:1000 可以在 10001的帮助下变成 0000 和 10101)。凑不出来答案就是n-1。

            多想几组数据还是能想明白的(现场赛你怎么菜的和狗一样?)

    C题

             题面:给出一个n位的数字,如果两个相邻位置的奇偶性不同,那么就可互换他们的位置。互换次数不限,问最终可以获得的最小数字是多少,可以有前导零。其实就是字符序最小。

             做法:遍历一边字符串,然后存下每一个奇数和偶数的位置。然后我们在遍历一边把他们放回去就可以了,放回去的原则是先放小的那个。想想就知道这样的序列是合法的并且是最优的(不会证明,就只能想想)。

     1 #include <stdio.h>
     2 #include <set>
     3 #include <string.h>
     4 using namespace std;
     5 char s[300009], res[300009];
     6 set <int> :: iterator it;
     7 set <int> st[2];
     8 int main()
     9 {
    10     int T, len;
    11     scanf("%d", &T);
    12     while(T--)
    13     {
    14         scanf("%s", s+1);
    15         len = strlen(s+1);
    16         st[0].clear(); st[1].clear();
    17         for(int i = 1; i <= len; i++) 
    18         st[(s[i]-'0')%2].insert(i);
    19         
    20         for(int i = 1; i <= len; i++)
    21         {
    22             if(st[0].empty()) 
    23             {
    24                 res[i] = s[*st[1].begin()]; 
    25                 st[1].erase(st[1].begin());
    26                 continue;
    27             }
    28             if(st[1].empty()) 
    29             {
    30                 res[i] = s[*st[0].begin()]; 
    31                 st[0].erase(st[0].begin());
    32                 continue;
    33             }
    34             
    35              if(s[*st[0].begin()] < s[*st[1].begin()])
    36             {
    37                 res[i] = s[*st[0].begin()]; 
    38                 st[0].erase(st[0].begin());
    39             }else{
    40                 res[i] = s[*st[1].begin()]; 
    41                 st[1].erase(st[1].begin());
    42             }
    43         }
    44         res[len+1] = '\0';
    45         
    46         printf("%s\n", res+1);
    47     }
    48 }

    D题

             题面:说有一个老板要给员工发工资了,每个员工的有一个工资的范围Li和Ri,老板只有S那么多的钱,问怎么发工资才能让所有人工资的中文数最大。

             做法:看到求最大值,然后正向思考发现没有好的贪心策略,那么就可以考虑一手二分。二分的板子一敲,然后问题来了,怎么check。

             比如现在要check  X这个值

             那么对于所有Li  >  X的员工来说只能是在中位数的右边,对于Ri  <  X的员工来说只能是在中位数的左边,对于这两种情况最小花费的增加值都是Li(手算模拟就可以想明白)。其他的就是放哪里都无所谓,可以最优分配。

    先可以数一下必然放左右位置的各有多少,如果其中任意值大于n/2 那么说明是不行的。然后我们把随意放的按Li从小到达排个序,如果左边还没满那么就对所需费用加Li,满了就加X。最后判断费用是否小于老板有的钱就可以。

    但是这里有一个问题,二分要求的是在check的过程中,趋势只有一个,就是大于一个值就都行或者都不行,这样我们才可以二分。但是在这题里面如果X小了或者大了都会出现这样的情况,所以我们需要去掉一个。题目告诉我们,老板最起码可以负担一个最低工资,我们对最低工资排个序,那么二分的下界就是第n/2 + 1个人的 L 。然后就可以很愉快的二分了。

     1 #include <stdio.h>
     2 #include <cstring>
     3 #include <vector>
     4 #include <set>
     5 #include <algorithm>
     6 using namespace std;
     7 struct node
     8 { 
     9     int l, r;
    10     bool operator < (struct node a)
    11     {
    12         return l < a.l;
    13     }
    14 }a[200009];
    15 typedef long long ll;
    16 int T, n, l, r, mid;
    17 ll sum;
    18 bool check(int x)
    19 {
    20     vector <struct node> ve;
    21     ve.clear();
    22     int num = 0;
    23     ll res = 0;
    24     for(int i = 1; i <= n; i++)
    25         if(a[i].r<x) 
    26         {
    27             res += a[i].l;
    28             num++;
    29         }
    30         else if(a[i].l>x) 
    31         {
    32             res += a[i].l;
    33         }else ve.push_back(a[i]);
    34     
    35     if(num>=n/2+1) return false;
    36     
    37     int size = ve.size();
    38     
    39     for(int i = 0; i < size; i++)
    40     if(num<n/2)
    41     {
    42         res += ve[i].l;
    43         num++;
    44     }else res += x;
    45     
    46     return res <= sum;
    47 }
    48 
    49 int main()
    50 {
    51     scanf("%d", &T);
    52     while(T--)
    53     {
    54         scanf("%d %lld", &n, &sum);
    55         for(int i = 1; i <= n; i++)
    56         scanf("%d %d", &a[i].l, &a[i].r);
    57     
    58         r = 1e9;
    59         
    60         sort(a+1, a+1+n);
    61         l = a[n/2+1].l; 
    62     //    printf("%d %d\n", l, r);
    63         while(l<=r)
    64         {
    65             mid = (l+r) / 2;
    66             if(check(mid))
    67             {
    68                 if(!check(mid+1)) break;
    69                 l = mid+1;
    70             }else r = mid - 1;
    71         }
    72         
    73         printf("%d\n", mid);
    74     }
    75 }

    E题

             题面:有n个选民每个人有一个Mi和Pi,Mi表示如果此时已经有那么多人投了你一票,那么他就会跟风投你一票,Pi表示你可以花那么多钱来买下他手里的选票。问最少要多少钱,才能让大家都投你一票。

             做法:对于Mi==0的人来说,他们的选票就是白给的,可以直接拿走,白嫖他。把剩下的人按Mi从小到大排序。然后从后往前遍历,如果现在已经获得的选票+[ i - 1(表示前面的人都把票给你了)] 大于等于Mi那么说明这个人是不需要花钱的,否则的话我们就收买p最小的的选民(包括i在内的已有的选民),可以用multiset或者priority_queue。

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <set>
     4 using namespace std;
     5 struct node
     6 {
     7     int m, p;
     8     bool operator < (struct node a)
     9     {
    10         if(m==a.m) return p > a.p;
    11         return m < a.m;
    12     }
    13 }a[200009], tmp;
    14 int main()
    15 {
    16     int T, n, pos, num;
    17     long long res;
    18     scanf("%d", &T);
    19     multiset <int> st;
    20     while(T--)
    21     {
    22         res = pos = num = 0;
    23         scanf("%d", &n);
    24         for(int i = 1; i <= n; i++)
    25         {
    26             scanf("%d %d", &tmp.m, &tmp.p);
    27             if(tmp.m!=0) a[++pos] = tmp;
    28             else num++;
    29         }
    30         sort(a+1, a+1+pos);
    31         st.clear();
    32         for(int i = pos; i >= 1; i--)
    33         {
    34             st.insert(a[i].p);
    35             if(num + i - 1 >= a[i].m) continue;
    36             num++;
    37             res += *st.begin();
    38             st.erase(st.begin());
    39         }
    40     
    41         printf("%lld\n", res);
    42     }
    43 }

            

            

            

  • 相关阅读:
    CodeForces 681D Gifts by the List (树上DFS)
    UVa 12342 Tax Calculator (水题,纳税)
    CodeForces 681C Heap Operations (模拟题,优先队列)
    CodeForces 682C Alyona and the Tree (树上DFS)
    CodeForces 682B Alyona and Mex (题意水题)
    CodeForces 682A Alyona and Numbers (水题,数学)
    Virtualizing memory type
    页面跳转
    PHP Misc. 函数
    PHP 5 Math 函数
  • 原文地址:https://www.cnblogs.com/loenvom/p/11917820.html
Copyright © 2011-2022 走看看