Codeforces Round #654 (Div. 2)A-E1
Posted lonely-wind-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #654 (Div. 2)A-E1相关的知识,希望对你有一定的参考价值。
题目链接:https://codeforces.com/contest/1371
题目说明:
A.Magical Sticks(简单思维)
B.Magical Calendar(思维)
C.Cookie for you(简单思维)
D.Grid-00100(规律构造)
E1.Asterism(Easy Version)--暴力
E2.Asterism(Hard Version)--无能为力
F.Raging Thunder(无能为力)
A.Magical Sticks(简单思维)
题目大意:给你n根木棍,长度为1到n,你可以将任意两根棍子拼接形成一根新的棍子,问,最多能够使得多少根木棍的长度一样。
4 1 2 3 4
1 1 2 2
。。。手动写几个数据就知道了,全部都是向最大的数靠拢,那么答案很明显了,我们给个奇数和偶数看看就知道了:
1 2 3 4->1-3,4共2个
1 2 3 4 5->1-4,2-3,5共3个
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int main() { int t,n; scanf ("%d",&t); while (t--){ scanf ("%d",&n); int ans=(n+1)/2; printf("%d ",ans); } return 0; }
B.Magical Calendar(思维)
题目大意:规定每周的天数为1~R中的任意一个数。现在要选择连续的N天,在日历上将这N天涂上颜色。问对于1~R不同的天数,总共有多少种不一样的形状。
5 3 4 3 2 3 1 13 7 1010000 9999999
4 3 1 28 510049495001
实际上每周的天数决定的是表格的宽度,而表格的长度是无限的。对于天数小于每周天数的情况,那么只能涂在同一行了,总的个数就是1。对于大于每周天数的情况,第一周的选择可以是只涂最后一格、只涂最后两格.....涂满整周,每种涂法形状都不同,因此答案就是每周的天数r。那么从1到r,我们只需分类讨论一下就完事了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { int t; int n,r; scanf ("%d",&t); while (t--){ scanf ("%d%d",&n,&r); if (n>r) { ll ans=(1LL+r)*r/2; printf("%lld ",ans); } else { ll ans=(1LL+n-1)*(n-1)/2+1; printf("%lld ",ans); } } return 0; }
C.Cookie for you(简单思维)
题目大意:有a个vanilla cookies和b个chocolate cookies,现在要邀请n个性格属性为1的客人和m个性格属性为2的客人。性格属性为1的客人吃cookie的习惯是:如果 a > b 则吃一个vanilla cookie,否则吃一个chocolate cookie。性格属性为2的客人的习惯与属性1的相反。现在给定a、b、n、m,问能否安排客人前来聚会的顺序,使得每一个人都有cookie吃。
6 2 2 1 2 0 100 0 1 12 13 25 1 27 83 14 25 0 0 1 0 1000000000000000000 1000000000000000000 1000000000000000000 1000000000000000000
Yes No No Yes No Yes
值得注意的是他并不是一个一个地邀请,而是一类人一类人地邀请。。。然后就很简单了,最优的决策肯定是先邀请吃少的那部分人。那么答案也就出来了了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { int t; scanf ("%d",&t); while (t--){ ll a,b,n,m; scanf ("%lld%lld%lld%lld",&a,&b,&n,&m); if (a+b<n+m) {printf("No "); continue;} if (min(a,b)<m) {printf("No "); continue;} printf("Yes "); } return 0; }
D.Grid-00100(规律构造)
题目大意:给你一个n*n的01矩阵,其中1的个数为k,定义矩阵A的一个属性$F(A),R_i,C_i$,其中$R_i$ 为01矩阵第 $i$ 行中 1 的数量。$C_i$ 为01矩阵第 $i$ 列中 1 的数量 。其中$F(A)=(Max(R)-Min(R))^2+(Max(C)-Min(C))^2$,要使得$F(A)$值最小,请你构造这样的01矩阵,并输出$F(A)$值
4 2 2 3 8 1 0 4 16
0 10 01 2 111 111 101 0 0 0 1111 1111 1111 1111
通过第一个样例我们就应该察觉到对角线优先放置是最优的,那么我们可以先对n*n的表格标号放置的顺序如下所示:
int flag=0,nb=1,line1=2,line2=1,zu=1; for (int i=1; i<=n; i++) id[i][i]=nb++,mp[nb-1]=node {i,i}; while (nb<=n*n) { if (!flag) { for (int i=line1; i<=n; i++) { int j=i-zu; id[i][j]=nb++; mp[nb-1]=node {i,j}; } flag^=1; line1++; } else { for (int i=line2; i<=zu; i++) { int j=i+(n-zu); id[i][j]=nb++; mp[nb-1]=node {i,j}; } flag^=1; zu++; } }
得到的id结果为:
1 14 11 8
5 2 15 12
9 6 3 16
13 10 7 4
然后按照这个顺序进行填充1就好了。
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=310; const int inf=1e8; int a[mac][mac],id[mac][mac]; struct node { int x,y; }mp[mac*mac]; int qpow(int x) {return x*x;} int main() { int t,n,m; scanf ("%d",&t); while (t--){ scanf ("%d%d",&n,&m); memset(a,0,sizeof a); memset(id,0,sizeof id); int flag=0,nb=1,line1=2,line2=1,zu=1; for (int i=1; i<=n; i++) id[i][i]=nb++,mp[nb-1]=node{i,i}; while (nb<=n*n){ if (!flag){ for (int i=line1; i<=n; i++){ int j=i-zu; id[i][j]=nb++; mp[nb-1]=node{i,j}; } flag^=1; line1++; } else { for (int i=line2; i<=zu; i++){ int j=i+(n-zu); id[i][j]=nb++; mp[nb-1]=node{i,j}; } flag^=1; zu++; } } for (int i=1; i<=m; i++){ int x=mp[i].x,y=mp[i].y; a[x][y]=1; } int min_r=inf,min_c=inf,max_c=0,max_r=0; for (int i=1; i<=n; i++) { int r=0,c=0; for (int j=1; j<=n; j++) r+=a[i][j],c+=a[j][i]; min_r=min(min_r,r);max_r=max(max_r,r); min_c=min(min_c,c);max_c=max(max_c,c); } printf ("%d ",qpow(max_c-min_c)+qpow(max_r-min_r)); for (int i=1; i<=n; i++){ for (int j=1; j<=n; j++) printf("%d",a[i][j]); printf(" "); } } return 0; }
E1.Asterism(Easy Version)--暴力
题目大意:你有n个敌人,每个敌人手中有a[i]个糖果,你初始的时候有x个糖果,现在你要和敌人对战,你可以决定敌人的排列顺序,其决战的规则为:你手中的糖果大于等于敌人的,则获胜,且额外获得一颗糖果。你要战胜所有的敌人。定义$f(x)$为当初始有$x$个糖果时有$f(x)$中排列使得你全胜,当$f(x)modp=0$ 这个答案是不够优秀的,反之则是优秀的,问你有多少个优秀的答案,并将其输出。
3 2 3 4 5
1 3
4 3 2 3 5 6
2 3 4
设置mx为敌人手中最大的糖果数,那么可以知道的是x的最小值为mx-n+1,最大值为mx-1。因为,大于等于最大值的时候无论怎么放都是OK的,那么方法有N!中,但p<N,所以N!%p=0。我们枚举x,判断x是否合法,判断函数如下:
int ok(int x,int p,int mx) { int ans=1,v=0; for (int i=1; i<=n; i++) if (a[i]<x) v++; for (int i=x; i<=x+n-1; i++){ if (i<=mx) v+=num[i]; ans=ans*v%p; v--; } return ans!=0; }
第i个位置有v种情况,那么我直接将答案乘以他就好了,然后拿走一种情况。
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=2e3+10; int a[mac],num[mac],n; int ok(int x,int p,int mx) { int ans=1,v=0; for (int i=1; i<=n; i++) if (a[i]<x) v++; for (int i=x; i<=x+n-1; i++){ if (i<=mx) v+=num[i]; ans=ans*v%p; v--; } return ans!=0; } int main() { int p,mx=0; scanf ("%d%d",&n,&p); for (int i=1; i<=n; i++) scanf ("%d",&a[i]),num[a[i]]++,mx=max(mx,a[i]); int flag=0,x; vector<int>ans; for (int i=mx-n+1; i<mx; i++){ if (i<=0) i=1; if (ok(i,p,mx)) ans.push_back(i); } printf("%d ",ans.size()); for (auto x:ans) printf("%d ",x); printf(" "); return 0; }
以上是关于Codeforces Round #654 (Div. 2)A-E1的主要内容,如果未能解决你的问题,请参考以下文章
D - Grid-00100(Codeforces Round #654 (Div. 2))
Codeforces Round #654 (Div. 2) A~E 题解
Codeforces Round #654 (Div. 2) B. Magical Calendar (结论)
Codeforces Round #436 E. Fire(背包dp+输出路径)