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,你可以将任意两根棍子拼接形成一根新的棍子,问,最多能够使得多少根木棍的长度一样。

Example
input
4
1
2
3
4
output
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;
}
View Code

 

B.Magical Calendar(思维)

题目大意:规定每周的天数为1~R中的任意一个数。现在要选择连续的N天,在日历上将这N天涂上颜色。问对于1~R不同的天数,总共有多少种不一样的形状。

Example
input
5
3 4
3 2
3 1
13 7
1010000 9999999
output
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;
}
View Code

 

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吃。

Example
input
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
output
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;    
}
View Code

 

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)$值

Example
input
4
2 2
3 8
1 0
4 16
output
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;
}
View Code

 

E1.Asterism(Easy Version)--暴力

题目大意:你有n个敌人,每个敌人手中有a[i]个糖果,你初始的时候有x个糖果,现在你要和敌人对战,你可以决定敌人的排列顺序,其决战的规则为:你手中的糖果大于等于敌人的,则获胜,且额外获得一颗糖果。你要战胜所有的敌人。定义$f(x)$为当初始有$x$个糖果时有$f(x)$中排列使得你全胜,当$f(x)modp=0$ 这个答案是不够优秀的,反之则是优秀的,问你有多少个优秀的答案,并将其输出。

Examples
input
3 2
3 4 5
output
1
3
input
4 3
2 3 5 6
output
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+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

Codeforces Round #726 (Div. 2) B. Bad Boy(贪心)