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

 

posted @ 2015-07-01 09:34  justPassBy  阅读(283)  评论(0编辑  收藏  举报