昨天的cf,被一堆烦心事搞得自己很无语。。又打了一场半夜的cf,发现自己还是菜的一匹,哎。
A. Equality
最长的1-K,字母相同的最长子序列。
直接找到1-K字母最少的各数乘以K就可了。
B. Non-Coprime Partition
把1-N分给两个集合,使得两个集合的和的gcd大于1。1,2的时候直接特判无解。当N大于2的时候,只要把一个集合全部分配奇数,另一个集合全部非配偶数,这样就肯定正确。
因为对于连续的几个数字,比如1,2,3,4,5,无论奇数的和或者偶数的和一定是中间那个数的倍数。
C. Gambling
一道博弈,两个人玩游戏,有两个操作,删去对方列表一个数,或者拿自己列表一个数。问最后游戏结束后A手里的数减去B手里的数后为多少。
把列表里的数放到一个大顶堆里面就可以了,考虑自己堆里面的最大值和对方对立面的最大值比较,如果自己的大,就拿自己的这个数,否则删去对方的这个数。注意考虑一下堆为空的情况。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(void){
priority_queue<int,vector<int>,less<int> > A,B;
int N,a,b;
scanf("%d",&N);
for(int i=1;i<=N;++i){
scanf("%d",&a);
A.push(a);
}
for(int i=1;i<=N;++i){
scanf("%d",&b);
B.push(b);
}
ll reA = 0,reB = 0;
int round = 0;
while(true){
if(A.size() == 0 && B.size() == 0){
break;
}
if(round % 2 == 0){
if(B.size() == 0){
reA += A.top();
A.pop();
}
else if(A.size() == 0){
B.pop();
}
else{
if(A.top() >= B.top()){
reA += A.top();
A.pop();
}
else{
B.pop();
}
}
}
else{
if(A.size() == 0){
reB += B.top();
B.pop();
}
else if(B.size() == 0){
A.pop();
}
else{
if(B.top() >= A.top()){
reB += B.top();
B.pop();
}
else{
A.pop();
}
}
}
round++;
}
printf("%I64d\n",reA-reB);
return 0;
}
D. Slime
给你N个数,每个数可以减去左边的数或者右边的数,问你最后能产生的最大结果是多少。
这个题目昨天被我读错了。。理解为只能向右吃,结果一直没有通过。。。
思路:
考虑一个正数和一个负数,那么肯定结果是正数,所以,如果列表中既有正数又有负数,那么结果一定是所有数的绝对值的和。
现在考虑全为负数,那么一定是从最大的那个负数向两边减去,相当于加上两边数的绝对值。
如果全为正数,那么就是从最小的那个正数,向一边减去,产生最大的负数,最后被一个正数给吃掉,也相当于是加上两边的绝对值。
这样就可以分三种情况进行计算了。
代码也很好写,注意考虑N=1,要进行特判。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 5e5+10;
const ll INF = 1e16+10;
int N;
ll a[MAX];
int main(void){
ll Min = INF,Max = -INF;
int C1 = 0,C2 = 0;
scanf("%d",&N);
ll sum = 0;
for(int i=1;i<=N;++i){
scanf("%I64d",&a[i]);
sum += abs(a[i]);
if(a[i] > Max) Max = a[i];
if(a[i] < Min) Min = a[i];
if(a[i] <= 0) C1++;
if(a[i] >= 0) C2++;
}
if(N == 1){
printf("%I64d\n",a[1]);
}
else{
if(C1 == N)
sum += 2*Max;
else if(C2 == N)
sum -= 2*Min;
printf("%I64d\n",sum);
}
return 0;
}