Codeforces 1371 A,B,C,D,E1,E2题解

91 篇文章 0 订阅
9 篇文章 0 订阅

This way

A. Magical Sticks:

现在有n个木棒,第i个木棒的长度为i,你每次可以将两根木棒合并,从而得到一根长度为他们长度之和的木棒。最终希望长度相同的木棒最多,问这个答案是多少

A题解:

那么很明显,第一根木棒和最后一根合并,第二根和倒数第二根合并。。。以此类推于是答案就是(n+1)/2

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        printf("%d\n",(n+1)/2);
    }
    return 0;
}

B. Magical Calendar:

你可以将一个星期的长度定义为1~r,他现在要涂色连续的n天,如果超过了最后一天,那么就在下一行的第一天开始。他要使得所有涂色过的格子连在一起,问你最终本质不同的涂色方法有多少。

B题解:

那么我们可以知道最大只能取到min(n-1,r),
然后长度为1时答案是1,长度为2时答案是2…以此类推
超出n-1的部分的答案总共是1,因为都是一条线段。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ll n,r;
        scanf("%lld%lld",&n,&r);
        if(r<n)
            printf("%lld\n",(1+r)*r/2);
        else
            printf("%lld\n",(1+n-1)*(n-1)/2+1);
    }
    return 0;
}

C. A Cookie for You

有a个香草饼,b个巧克力饼,现在有n个第一种客人,m个第二种客人按照你排好的次序来,每个客人来的时候都会拿一个饼,
如果来的客人是第一种,如果当前a>b,那么他会拿a,否则拿b
来的客人是第二种的话,如果当前a>b,那么他会拿b,否则拿a
如果这个客人没拿到饼,宴会失败。
问你最终宴会是否成功。

C题解:

首先如果a+b<n+m一定失败,然后如果m>min(a,b)的话,由于m每次都会拿比较少的那一个,所以其实m能够拿的数量是min(a,b).

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ll a,b,n,m;
        scanf("%lld%lld%lld%lld",&a,&b,&n,&m);
        if(m>min(a,b)||n+m>a+b)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}

D. Grid-00100

现在有n*n的格子,每个格子要么是0,要么是1,现在告诉你有k个1,并且定义
在这里插入图片描述
在这里插入图片描述
要使得f最小,问你构造方法。

D题解:

那么我们要使得f最小,肯定是要尽量让每行的1数量相同,每列的1数量相同,那么我们一次一次斜着放1即可,这样如果k%n=0的话,答案是0,否则答案是2.就像这个样子:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e2+5;
bool mp[N][N];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(mp,0,sizeof(mp));
        int n,k;
        scanf("%d%d",&n,&k);
        if(k%n)
            printf("2\n");
        else
            printf("0\n");
        while(k){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++,k--){
                    if(!k)break;
                    mp[j][(j+i)%n]=1;
                }
                if(!k)break;
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                printf("%d",mp[i][j]);
            printf("\n");
        }
    }
    return 0;
}

E1.Asterism (Easy Version):

定义f(x):
你一开始有x颗糖,现在有n个敌人,每个敌人有ai颗糖,你要去按照一个排列去战胜这些敌人,当你的糖的数量>=ai的时候,你就可以战胜他,赢了之后你就可以得到一颗糖。f(x)表示可以赢的排序的数量。
找到一些x使得f(x)不是p的倍数。

E1题解:

当然hard的题解也能用,但是数据范围不同就应该有不同的想法。
首先看到范围就知道是 O ( n 2 ) O(n^2) O(n2)的想法,那么我们首先可以选择枚举x,然后再从1到n枚举位置,用一个r维护我们当前右端第一个不能取到的位置,如果r-i是p的倍数,证明不行。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
vector<int>ans;
int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int x=1;
    for(int i=1;i<=n;i++)
        x=max(a[i]-i+1,x);
    for(;x<=a[n];x++){
        int r=1,f=0;
        for(int i=1;i<=n;i++){
            while(r<=n&&x+i-1>=a[r])
                r++;
            if((r-i)%p==0){
                f=1;
                break;
            }
        }
        if(!f)
            ans.push_back(x);
    }
    printf("%d\n",ans.size());
    for(int i:ans)
        printf("%d ",i);
    printf("\n");
    return 0;
}

E2.Asterism (Hard Version)题解:

它写个hard version,我以为很难啊,没想到原来是个水题?绝了
首先按照a从大到小排序,然后赢过第ai的最少需要的x是ai-i+1.那么从所有中取个最大值
然后我们可以知道,你每次能赢过的人的数量不能大于等于p,因为这样的话,当能取的区间慢慢缩小时,一定能取到p。
对于第i个数,如果你的值>=ai-i+p的话,就是违法的。那么只要在其中取个最小值,然后从左界到右界输出一下即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int l=1,r=1e9;
    for(int i=1;i<=n;i++)
        l=max(l,a[i]-i+1);
    for(int i=p;i<=n;i++)
        r=min(r,a[i]-i+p);
    if(l<r){
        printf("%d\n",r-l);
        for(int i=l;i<r;i++)
            printf("%d%c",i," \n"[i==r-1]);
    }
    else
        printf("0\n");
    return 0;
}

F. Raging Thunder(待定)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值