赞
踩
给定一个字符串,求最长子字符串,要求所有字符出现次数相同。注意,由于要求使用的字符数k已经给出,但是不一定全部出现在字符串里,所以可能只能构造空字符串。
很简单了,先将所有字符的出现次数统计出来。然后看k个字符出现次数最少的那个,然后将最小出现次数乘以k就行了。
- [n,k] = map(int, input().split())
- const = input()
- counting = {}
- for i in range(k):
- counting[chr(ord('A') + i)] = 0
- for i in const:
- counting[i] += 1
-
- ret = n
- for i,v in counting.items():
- ret = min(ret, v)
- print(ret*k)
-
-
给出n,将从1到n这n个数字分到两份,分别求和得到sum1和sum2,求gcd(sum1,sum2) > 1的的分割方法。打印是否可以分割,然后把分割打印出来。
这里有一点小技巧。很明显,对于n为1,2,都是没有结果的,但是对于大于等于3的n,都是有结果的。但是具体要怎么分呢?我们直到n个数字的和为 (1 + n ) * n /2。这里,和分两种。奇数,偶数。
1,对于和为偶数的情况,任何偶数减2都还是偶数。所以最简单的分配方法,就是2一波,剩下的一波。他们的gcd为2。
2,对于和为奇数的情况,需要考虑两种情况,
a,n为奇数,这个时候,中间数middle = (1 + n)/2,必定有middle * n = (n + 1) * n /2 。很明显了,这个时候,middle一波,剩下的数一波。gcd为middle=(n+1)/2
b,n为偶数,这个时候,(1+n)/2 = middle,但是这个middle不是整数。所以我们换一个middle,用n/2。同理,middle一波,剩下的数一波,gcd为middle=n/2
- n = int(input())
- if n <= 2:
- print("No")
- else:
- print("Yes")
- sum = (n + 1) * n / 2
- if(sum % 2 == 0):
- print("1 2")
- anotherLine = "%d 1" % (n - 1)
- for i in range(3,n + 1):
- anotherLine += " %d" % i
- print(anotherLine)
- else:
- if n % 2 == 0:
- middle = n /2
- else:
- middle = (n + 1) / 2
- print("1 %d" % (middle))
- anotherLine = "%d 1" % (n - 1)
- for i in range(2,n + 1):
- if i != middle:
- anotherLine += " %d" % i
- print(anotherLine)
-
A,B两人分别有一组数字,没人可以从自己的数组取一个数字,拿起来。或者从对手的数组取一个数字,移出,不放入任何人的口袋。两人数组清空之后,游戏结束。游戏结束后,两人手中分别求手上的数字之和。求两人在用最优策略时,两人的数字相差为多少。
这个策略用贪心即可。把两人手头的数字从大到小排序,每一轮,如果自己手头的最大的数字比对手大,就拿起来,否则,移除对手的数字。
嗯。。。就是我这代码晚上写的,不够简洁。。。。
- n = int(input())
- A = list(map(int, input().split()))
- B = list(map(int, input().split()))
-
- A = sorted(A,reverse = True)
- B = sorted(B,reverse = True)
-
- sA, sB = 0, 0
- i,j = 0,0
- turn = 1
- while True:
- turn += 1
- turn %= 2
- if i >= n and j >= n:
- break;
- if i == n:
- if turn == 1:
- #turn for b and a is list empty
- sB += B[j]
- j+=1
- continue
- if j == n:
- if turn == 0:
- #turn for a and b is list empty
- sA += A[i]
- i+=1
- continue
- if turn == 0:
- #turn for a
- if A[i] > B[j]:
- sA += A[i]
- i +=1
- elif A[i] < B[j]:
- j +=1
- else:
- j +=1
- else:
- if A[i] > B[j]:
- i += 1
- elif A[i] < B[j]:
- sB += B[j]
- j += 1
- else:
- i += 1
- print(sA-sB)
有一排史莱姆,他们可以吃自己左边或者右边的史莱姆。每个史莱姆有一个数值。每次吞噬,都用自己的数字减对方的数字。求所有史莱姆吞噬完,只剩一个史莱姆的时候,能得到的最大数字是多少。
这个策略也简单。
如果输入有正有负,则将所有数字的绝对值加起来,即可(很简单,从负数开始,一直用小的吃大的,不断积累,最后用正数吃负数即可)
如果输入全部为正或者全部为负,则将所有数字的绝对值加起来,然后减 2 乘以最小的绝对值即可。第一步用最小的绝对值吃旁边的史莱姆(或者被吃掉),得到一个有正有负的数列。然后重复上面有正有负的步骤。
- import sys
- n = int(input())
- line = list(map(int, input().split()))
-
- if n == 1:
- print(line[0])
- sys.exit(0)
-
- sum = 0
- minNum = 10 ** 9
- maxNum = -10**9
- for i in line:
- if minNum > i:
- minNum = i
- if maxNum < i:
- maxNum = i
- sum += abs(i)
- if minNum * maxNum < 0:
- print(sum)
- elif minNum < 0:
- print(sum - 2 * abs(maxNum))
- else:
- print(sum - 2 * abs(minNum))
有很多block,block左右分别有一种颜色,左右的,从所有block里面选一部分出来,同颜色的边可以拼在一起。求拼在一起的block的value的和最大为多少。
我一开始以为是动态规划,折腾了很久。后来看了别人的答案才知道,嗯。。。欧拉图。。。
我们把四个颜色看成四个点,一个block表示从一个点到另一个点的一条边。block的value就是边的权重。求一个子图,该子图构成欧拉回路,并且权重之和最大。
进一步,由于只有四个点,又是无向图,所以我们可以有这样的结论,要么刚好所有节点都是偶数度节点,要么有两个节点是奇数度节点,要么四个节点都是奇数度节点。这里其实只有最后一种情况不符合欧拉图的要求,这个时候需要去掉一条边,这样肯定有两个节点分别减少一个度,变成两个偶数度节点。于是问题变成了去掉那条边。
出题者给的答案是,我们只有16条边,整一个bitmap,遍历所有的边的组合。然后看哪个组合得到的和最大。时间复杂度为n * 2^16。嗯。。。。。其实挺好的。但是我觉得太复杂了。看了下答案,有复杂度为n的解。于是我研究了一下。奥,他们直接从一个节点开始dfs,遇到的节点加入进来,计算度数。如果有四个奇数度的节点在这个子图,那么需要去掉一条边,很多人直接拿一条权重最低的边一减就完事了,并且AC了。
感觉哪里不对劲的我把AC代码抄下来丢上去。跑test,一切都很愉悦,直到第117个test case,嗯???WA了?为嘛他能过,我一样的就WA,一看记录,比赛的时候只有116个test case。。。
仔细分析test case117,发现他的权重最小的那条边,是一个割边,去除之后,有一个节点从原来的欧拉图上面割裂开了。。。。看来codeforeces的测试用例也不是很全嘛。。。。
正确的做法是。将任意两个点(包括从自己出发到自己)的边的min值保存下来。先做一次dfs,这个dfs需要做的就是遍历四个点,将连通子图的权重和求出来,如果这个子图的奇数节点为4,那就丢掉这个结果。然后,遍历16条边,如果这个边在图里面出现了,不管是有一条还是几条,尝试将它抹去,然后做一次dfs,更新结果,再把这个边加回来。时间复杂度 4*4*n。很愉悦。
- #include <bits/stdc++.h>
-
- using namespace std;
-
- int deg[4];
- vector<int> e[4][4];
- bool was[4];
- unsigned int min_v[4][4];
-
- int sum, min_val, cnt_node, cnt_deg, res;
-
- vector<int> removed;
- void dfs(int u) {
- was[u] = true;
- cnt_deg += deg[u];
- cnt_node += 1;
- for (int c : e[u][u]) {
- sum += c;
- }
- for (int v = 0; v < 4; ++v) {
- if (!e[u][v].empty()) {
- if (u < v) {
- for (int c : e[u][v]) {
- sum += c;
- }
- }
- if (!was[v]) dfs(v);
- }
- }
- }
-
- void check()
- {
- memset(was, 0, sizeof(was));
- for (int i = 0; i < 4; ++i) if (!was[i]) {
- sum = 0;
- cnt_deg = 0;
- dfs(i);
- if (cnt_deg != 4) {
- res = max(res, sum);
- }
- }
- // printf("res:%d\n", res);
- }
-
- //void print_all_edeges()
- //{
- // for (int i = 0; i < 4; ++i) {
- // for (int j = 0; j <= i; ++j) {
- // if(e[i][j].size() > 0)
- // {
- // printf("i:%d, j:%d, size:%d\n", i + 1, j +1, e[i][j].size());
- // }
- // }
- // }
- // printf("\n");
- //}
- int main() {
- int n; cin >> n;
-
- res = 0;
- memset(min_v, 0xff, sizeof(min_v));
- for (int i = 0; i < n; ++i) {
- int u, v, c;
- cin >> u >> c >> v;
- deg[--u] ^= 1;
- deg[--v] ^= 1;
- e[u][v].push_back(c);
- if(c < min_v[u][v])
- {
- min_v[u][v]=c;
- min_v[v][u]=c;
- }
- if (u != v) e[v][u].push_back(c);
- }
-
- check();
- for (int j = 0; j < 4; j++)
- {
- for(int k = 0; k <= j; k++)
- {
- //delete one edge
- if(e[j][k].size() > 0)
- {
- auto i = e[j][k].begin();
- // printf("min_v[j][k] is :%d %d\n", min_v[j][k], min_v[k][j]);
- for(;i != e[j][k].end(); i++)
- {
- if(*i == min_v[j][k])
- {
- e[j][k].erase(i);
- break;
- }
- }
- auto it = e[k][j].begin();
- if(j!=k)
- {
- for(;it != e[k][j].end(); it++)
- {
- if(*it == min_v[k][j])
- {
- e[k][j].erase(it);
- break;
- }
- }
- }
- // printf("after remove %d, %d\n", k + 1, j+ 1);
- // print_all_edeges();
- deg[j] ^= 1;
- deg[k] ^= 1;
- check();
- //add back after check
- e[j][k].push_back(min_v[j][k]);
- if(j!=k)e[k][j].push_back(min_v[j][k]);
- deg[j] ^= 1;
- deg[k] ^= 1;
- // printf("after recover\n");
- // print_all_edeges();
- }
- }
- }
- cout << res << endl;
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。