codeforece Round#311 BCDE

B题

给我们n,m ,  m表示茶壶的容量

接下来2*n个数字,表示茶杯的容量,将这些茶杯分给n个男孩和n个女孩

可以倒x毫升的茶水给每个女孩,那么就要倒2x毫升的茶水给男孩,当然了,茶杯要装的下,且茶壶的水足够多

问最多能倒多少毫升?

思路:将茶杯按容量从下到大排序,那么前n个茶杯一定分给女孩,后n个茶杯分给男孩。那么只要将第一个茶杯的容量作为上界,0作为下界,二分枚举x,

每次统计后n个茶杯的容量是不是>=2x,如果是,那么说明该容量是可行的。 但是最终的数据测试却错了, 因为精度要达到1e-11才能正确,不知道为什么

 1 #include <stdio.h>

 2 #include <string.h>

 3 #include <stdlib.h>

 4 #include <algorithm>

 5 #include <iostream>

 6 #include <queue>

 7 #include <stack>

 8 #include <vector>

 9 #include <map>

10 #include <set>

11 #include <string>

12 #include <math.h>

13 using namespace std;

14 #pragma warning(disable:4996)

15 typedef long long LL;                   

16 const int INF = 1<<30;

17 const double eps = 1e-11;

18 /*

19 

20 

21 */

22 int a[200000 + 10];

23 int main()

24 {

25     int n, w;

26     while (scanf("%d%d", &n,&w) != EOF)

27     {

28         int m = 2 * n;

29         for (int i = 0; i < m; ++i)

30         {

31             scanf("%d", &a[i]);

32         }

33         sort(a, a + m);

34         double low = 0, high = a[0], mid;

35         int cnt;

36         double tmp;

37         while (high - low >= eps)

38         {

39             mid = (high + low) / 2;

40             cnt = 0;

41             for (int i = 0; i < m; ++i)

42             if (mid * 2 <= a[i])

43                 cnt++;

44             if (cnt >= n)

45             {

46                 tmp = mid * 3 * n;

47                 if (tmp<w)

48                     high = mid;

49                 else

50                     low = mid;

51             }

52             else

53                 high = mid;

54         }

55         printf("%f\n", mid * 3 * n);

56         

57     }

58     return 0;

59 }
View Code

比完看了别人代码才知道,有更简单的方法, 只要去w/3/n, a[0], a[n]/2 的最小值就好了

 1 #include <stdio.h>

 2 #include <string.h>

 3 #include <stdlib.h>

 4 #include <algorithm>

 5 #include <iostream>

 6 #include <queue>

 7 #include <stack>

 8 #include <vector>

 9 #include <map>

10 #include <set>

11 #include <string>

12 #include <math.h>

13 using namespace std;

14 #pragma warning(disable:4996)

15 typedef long long LL;                   

16 const int INF = 1<<30;

17 const double eps = 1e-11;

18 /*

19 

20 

21 */

22 int a[200000 + 10];

23 int main()

24 {

25     int n, w;

26     double ans = 0;

27     while (scanf("%d%d", &n,&w) != EOF)

28     {

29         int m = 2 * n;

30         for (int i = 0; i < m; ++i)

31         {

32             scanf("%d", &a[i]);

33         }

34         sort(a, a + m);

35         ans = (double)w / 3 / n;

36         ans = min(ans, (double)a[0]);

37         ans = min(ans, (double)a[n] / 2);

38         printf("%lf", ans*3*n);

39     }

40     return 0;

41 }
View Code

 

C题

给我们n,表示有n条桌腿,

然后接下来n个数字,Li表示桌腿的长度,

再接下来n个数组,di表示砍掉第i的桌腿的费用。

一个桌子要是稳定的,要求桌子最长的桌腿的条数占总条数的一半以上

问使得桌子稳定的最小花费

思路:将桌腿按长度排序,然后遍历桌腿,枚举桌腿的长度x作为最长的桌腿,那么比x长的桌腿应该去掉,

比x长的桌腿都排在x后面,所以我们可以维护一个后缀和,使得可以在O(1)的时间内获得砍掉比x长的所有桌腿的费用

设长度为x的桌腿有cnt条,那么要将比x短的桌腿砍掉剩下cnt-1条即可。 砍的时候,肯定是先砍费用小的。

比赛时的想法是用优先队列维护一个费用队列,队头的费用最小。但是时间复杂度超了(不去算算法的时间复杂度果然是不好的习惯)

其实费用的取值是1-->200,所以只要用个标记数组来标记,每次只要遍历标记数组就可以了。

  1 #include <stdio.h>

  2 #include <string.h>

  3 #include <stdlib.h>

  4 #include <algorithm>

  5 #include <iostream>

  6 #include <queue>

  7 #include <stack>

  8 #include <vector>

  9 #include <map>

 10 #include <set>

 11 #include <string>

 12 #include <math.h>

 13 #include <functional>

 14 using namespace std;

 15 #pragma warning(disable:4996)

 16 typedef long long LL;                   

 17 const int INF = 1<<30;

 18 /*

 19 

 20 */

 21 const int N = 100000 + 10;

 22 struct Node

 23 {

 24     int l, d;

 25     bool operator<(const Node&rhs)const

 26     {

 27         return l < rhs.l;

 28     }

 29 }a[N];

 30 int suffix[N],c[N];

 31 void input(int &x)

 32 {

 33     char ch = getchar();

 34     while (ch < '0' || ch>'9')

 35         ch = getchar();

 36     x = 0;

 37     while (ch >= '0' && ch <= '9')

 38     {

 39         x = x * 10 + ch - '0';

 40         ch = getchar();

 41     }

 42 }

 43 int main()

 44 {

 45     int n, i, j, ans, k, total;

 46     while (scanf("%d", &n)!=EOF)

 47     {

 48         total = 0;

 49         for (i = 0; i < n; ++i)

 50             input(a[i].l);

 51         for ( i = 0; i < n; ++i)

 52             input(a[i].d);

 53             

 54         sort(a, a + n);

 55         for (i = 0; i < n; ++i)

 56              suffix[i] = a[i].d;

 57         for (i = n - 2; i >= 0; --i)

 58             suffix[i] += suffix[i + 1];

 59         i = 0;

 60         ans = INF;

 61         while (i < n)

 62         {

 63             int tmp = a[i].l;

 64             j = i;

 65             while (i < n && a[i].l == tmp)

 66                 i++;

 67             int cnt = i - j;

 68             tmp = 0;

 69             //砍掉比x更长的桌腿

 70             if (i<n)

 71                 tmp = suffix[i];

 72             //total统计的是比x短的桌腿条数

 73             int t = total;

 74             

 75             for (k = 1; k <= 200; ++k)

 76             {

 77                 if (t < cnt)

 78                     break;

 79                 if (t - c[k] >= cnt - 1)

 80                 {

 81                     tmp += c[k] * k;

 82                     t -= c[k];

 83                 }

 84                 else 

 85                 {

 86                     tmp += k * (t - cnt + 1);

 87                     break;

 88                 }

 89             }

 90             

 91             for (k = j; k < i; ++k)

 92             {

 93                 c[a[k].d]++;

 94                 total++;

 95             }

 96             ans = min(ans, tmp);

 97         }

 98         printf("%d\n", ans);

 99     }

100     return 0;

101 }
View Code

 

D题:

给定一个图,问最少要加多少条边才使得图有长度为奇数的环。并输出方案数。

第一种情况:如有m=0,那么考虑一个环最少有3个点,3条边,所以我们要从n个点中选3个点,并且加上3条边就可以形成环

方案书是C(n,3)

第二种情况:每个点的度数不超过1(即图的最大连通分量只有2个点),那么只要加2条边,且方案数为   2个点的连通分量加独立的点形成的方案数(n-2*m)*n  

+ 2个点的连通分量加2个点的连通分量所形成环的方案书 2*m(m-1)

第三种情况:那么肯定最大连通分量有3个点,那么只要加1条边就可以了。所以只要将图染色,将黑色的点,或者白色的点连起来就形成环了

方案数是所有连通分量的 C(黑色,2) + C(白色,2)

当然了,如果图本身就存在奇数环, 那么输出0 1 就好了

 1 #include <stdio.h>

 2 #include <string.h>

 3 #include <stdlib.h>

 4 #include <algorithm>

 5 #include <iostream>

 6 #include <queue>

 7 #include <stack>

 8 #include <vector>

 9 #include <map>

10 #include <set>

11 #include <string>

12 #include <math.h>

13 using namespace std;

14 #pragma warning(disable:4996)

15 typedef long long LL;                   

16 const int INF = 1<<30;

17 /*

18 

19 */

20 const int N = 1000000 + 10;

21 vector<int> g[N];

22 int d[N];

23 int color[N];

24 bool hasOddCycle;

25 void dfs(int u, int fa,int &cnt, int &black)

26 {

27     

28     for (int i = 0; i < g[u].size(); ++i)

29     {

30         int v = g[u][i];

31         if (v == fa) continue;

32         if (color[v] == -1)

33         {

34             color[v] = color[u] ^ 1;

35             black += color[v];

36             cnt += 1;

37             dfs(v, u, cnt, black);

38         }

39         else if (color[u] == color[v])

40         {

41             hasOddCycle = true;

42         }

43         

44     }

45 }

46 int main()

47 {

48     int n, m, a, b;

49     bool flag = false;

50     scanf("%d%d", &n, &m);

51     if (m == 0)

52     {

53         printf("%d %I64d\n", 3, (LL)n*(n - 1)*(n-2) / 6);

54         return 0;

55     }

56     for (int i = 0; i < m; ++i)

57     {

58         scanf("%d%d", &a, &b);

59         g[a].push_back(b);

60         g[b].push_back(a);

61         d[a]++;

62         d[b]++;

63         if (d[a]>1 || d[b] > 1)

64             flag = true;

65     }

66     if (!flag)

67     {

68         printf("%d %I64d\n", 2, (LL)(n - 2 * m)*m + (LL)2 * m*(m - 1));

69         return 0;

70     }

71     memset(color, -1, sizeof(color));

72     LL ans = 0;

73     int cnt, black;

74     for (int i = 1; i <= n; ++i)

75     {

76         if (color[i] == -1)

77         {

78             cnt = black = 1;

79             color[i] = 1;

80             dfs(i, -1, cnt, black);

81             ans += (LL)black*(black - 1) / 2 + (LL)(cnt - black)*(cnt - black - 1) / 2;

82         }

83         if (hasOddCycle)

84             break;

85     }

86     if (hasOddCycle)

87         printf("%d %d\n", 0, 1);

88     else

89         printf("%d %I64d\n", 1, ans);

90 

91     return 0;

92 }
View Code

 

E题

用dp的方法在O(n*n)的时间内求出所有的half-palindrome. 然后将所有的子串都插入字典树中,时间复杂度同样是O(n*n),然后dfs到第k个half-palindrome

dfs的时间复杂度同样是O(n*n),因为字典树的节点数不超过O(n*n)

 1 #include <stdio.h>

 2 #include <string.h>

 3 #include <stdlib.h>

 4 #include <algorithm>

 5 #include <iostream>

 6 #include <queue>

 7 #include <stack>

 8 #include <vector>

 9 #include <map>

10 #include <set>

11 #include <string>

12 #include <math.h>

13 using namespace std;

14 #pragma warning(disable:4996)

15 typedef long long LL;                   

16 const int INF = 1<<30;

17 /*2

18 

19 */

20 int root, size, k, m = -1;

21 const int N = 5000 + 10;

22 bool ok[N][N];

23 char str[N], ans[N];

24 struct Trie

25 {

26     int cnt, next[2];

27     void init()

28     {

29         cnt = 0;

30         next[0] = next[1] = -1;

31     }

32 }trie[N*N];

33 

34 void add(int i, int n)

35 {

36     int cur = root;

37     for (int j = i; j < n; ++j)

38     {

39         if (trie[cur].next[str[j] - 'a'] == -1)

40         {

41             trie[size].init();

42             trie[cur].next[str[j] - 'a'] = size++;

43         }

44         cur = trie[cur].next[str[j] - 'a'];

45         if (ok[i][j])

46             trie[cur].cnt++;

47     }

48 }

49 void dfs(int cur)

50 {

51     k -= trie[cur].cnt;

52     if (k <= 0)

53     {

54         printf("%s\n", ans);

55         exit(0);

56     }

57     for (int i = 0; i < 2; ++i)

58     {

59         if (trie[cur].next[i] != -1)

60         {

61             ans[++m] = 'a' + i;

62             dfs(trie[cur].next[i]);

63             ans[m--] = 0;

64         }

65     }

66 }

67 int main()

68 {

69     scanf("%s%d", str,&k);

70     int n = strlen(str);

71     size = 1;

72     trie[root].init();

73     for (int len = 1; len <= n; ++len)

74     {

75         for (int i = 0; i <= n - len; ++i)

76         {

77             int j = i + len - 1;

78             if (j - i <= 3)

79                 ok[i][j] = str[i] == str[j];

80             else

81                 ok[i][j] = str[i] == str[j] && ok[i + 2][j - 2];

82         }

83     }

84     for (int i = 0; i < n; ++i)

85         add(i, n);

86     dfs(root);

87     return 0;

88 }
View Code

 

你可能感兴趣的:(round)