给定一个字符串,求最长子字符串,要求所有字符出现次数相同。注意,由于要求使用的字符数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
using namespace std;
int deg[4];
vector e[4][4];
bool was[4];
unsigned int min_v[4][4];
int sum, min_val, cnt_node, cnt_deg, res;
vector 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;
}