Codeforces Round #664 (Div. 2)
A题:https://codeforces.ml/contest/1395/problem/A
思路:当4个数里只有1个或0个奇数的时候,才能构成回文。题意给的操作是将前3个数分别减1,最后一个数加3,如果进行两次操作则加减的都是一个偶数,也就意味着不影响原来4个数的奇偶性。那么我们只需要进行一次操作即可。
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[])
{
int t;
scanf("%d",&t);
while(t--)
{
int r,g,b,w;
int ans = 0;
scanf("%d %d %d %d",&r,&g,&b,&w);
if (r % 2 == 1) ans ++;
if (g % 2 == 1) ans ++;
if (b % 2 == 1) ans ++;
if (w % 2 == 1) ans ++;
if (ans <= 1) printf("Yes\n");
else
{
if (r == 0 || g == 0 || b == 0) printf("No\n");
else
{
r-=1;
g-=1;
b-=1;
w+=3;
ans = 0;
if (r % 2 == 1) ans ++;
if (g % 2 == 1) ans ++;
if (b % 2 == 1) ans ++;
if (w % 2 == 1) ans ++;
if (ans <= 1) printf("Yes\n");
else printf("No\n");
}
}
}
return 0;
}
B题:https://codeforces.ml/contest/1395/problem/B
写的时候当成“兵”写了,按蛇形一直输出,然后wa得生活不能自理,虽然也是能过的但是代码冗长,导致后面缝缝补补让我及其头疼。然后看了大佬的代码,,,orz
#include <bits/stdc++.h>
using namespace std;
int n,m,a,b;
int print(int x,int y)
{
printf("%d %d\n",x,y);
for (int i = 1; i <=m; ++i) if (i != y) printf("%d %d\n",x,i);
return y == m ? m-1 : m;
}
int main(int argc, char const *argv[])
{
scanf("%d%d%d%d",&n,&m,&a,&b);
b = print(a,b);
for (int i = 1; i <= n; ++i)
{
if (i == a) continue;
b = print(i,b);
}
return 0;
}
思路就是每一行都从这一行的第一个输出,将这一行输出完之后返回结束处的列下标,然后进入下一行。真是简洁明了。
C题:https://codeforces.ml/contest/1395/problem/C
比赛的时候没时间写了,都是b害的啊......
最后的ans是由n个c做或运算得到的。首先我们要知道按位或,有1取1,意思就是a|b的结果一定大于等于a和b的最大值,那我们将ans与n个c里的任意一个做或运算,其结果必须为ans,那暴力跑每一个ans,让每个ci都跟ans做一次或运算就能找到我们要的ans了。
#include <bits/stdc++.h>
using namespace std;
int n,m,a[211],b[211];
int check(int x)
{
for (int i = 1; i <=n; ++i)
{
bool flag = 0;
for (int j = 1; j <=m; ++j)
{
if (((a[i] & b[j]) | x) == x)
{
flag = 1;
break;
}
}
if (!flag) return 0;
}
return 1;
}
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int j = 1; j <= m; j++) scanf("%d", &b[j]);
for(int i = 0; i <= 511; i++)
if(check(i)) printf("%d\n", i), exit(0);
return 0;
}
D题:https://codeforces.ml/contest/1395/problem/D
思路:求出前缀和,暴力取了几天大于m,维护ans即可。
代码中第二个for循环获取大于m和小于m的分界线
第三for计算前缀和
第4个for中,每取一个大于m就要减去m天,故n/(d+1)是指n天里最多能取几个m,n-cnta是指着n天里总共有几天大于m,两者取一个较小值就是我们暴力的范围。
取了i天n-(d+1)*i得到还剩下的天数。
最后qzh[n] - qzh[n-i] + qzh[cnta] - qzh[max(cnta - g,0)]是指,取i个大于m天就得到qzh[n] - qzh[n-i] ,然后要扣除d*i天,由于是排序的肯定从前往后扣,那就是qzh[cnta] - qzh[max(cnta - g,0)],其中qzh[cnta]是前面小于m的总和,qzh[max(cnta - g,0)]是指当剩下的天数>小于m的天数的时候,那么去掉的天数可以是>m的那一部分,所以这里直接是0,当剩下的天数<小于m的天数的时候,则要从小于m的天里扣除。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,d,a[100011],cnta;
ll ans,qzh[100011];
int main(int argc, char const *argv[])
{
scanf("%d%d%d",&n,&d,&m);
for (int i = 1; i <=n; ++i) scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(int i = 1; i <= n; i++) if(a[i] <= m) cnta = i;
if(cnta != n) --n;
for(int i = 1; i <= n; i++) qzh[i] = qzh[i - 1] + a[i];
for(int i = 0; i <= min(n / (d + 1), n - cnta); i++) {
int g = n - (d + 1) * i;
ans = max(ans, qzh[n] - qzh[n - i] + qzh[cnta] - qzh[max(cnta - g, 0)]);
}
printf("%lld\n", ans + a[n + 1]);
return 0;
}