给我们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 }
比完看了别人代码才知道,有更简单的方法, 只要去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 }
给我们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 }
给定一个图,问最少要加多少条边才使得图有长度为奇数的环。并输出方案数。
第一种情况:如有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 }
用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 }