【CF-1371 C-E2】

Codeforces Round #654 (Div. 2)

C.

题意

有 a 个香草饼干和 b 个巧克力饼干,以及两种类型的客人:

  1. 如果香草饼干的数量 > 巧克力饼干的数量,那么他会吃掉香草饼干,否则会吃掉巧克力饼干
  2. 如果巧克力饼干的数量 < 香草饼干的数量,那么他会吃掉巧克力饼干,否则会吃掉香草饼干

有 n 个 1 类型的客人,m 个 2 类型的客人,问是否可以满足这些客人的要求。

思路

简言之,就是 1 类型的人吃多的,2 类型的人吃少的。

如果最少的饼干数量比 2 类型人还少,或者饼干总数没有人数多,肯定无法满足所有客人的要求。

如果最少的饼干数量大于 2 类型的人,那么先让 1 类型的人吃,直到满足 1 类型的所有人或者最少的饼干数量等于 2 类型的人,这时让所有 2 类型的人吃,再让所有 1 类型的人吃。

代码

#include <bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 2e6 + 10;

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ll a,b,n,m;
        scanf("%lld%lld%lld%lld",&a,&b,&n,&m);
        if(min(a,b)<m||a+b<n+m) printf("No\n");
        else printf("Yes\n");
    }
    // system("pause");
    return 0;
}

D.

题意

给出整数 n , k,让构造出一个 n * n的 01 矩阵,满足一下条件:

  1. 矩阵中 1 的个数为 k 。
  2. 矩阵中 1 的个数 最多的行 和 最少的行 的差值的平方+ 最多的列 和 最少的列 的差值的平方

思路

直接把行和列分开来看。

当 n == 4 的时候,行的分配:

1 2 3 4 1 2 3 4 1 2 3 4...

列的分配:

1 2 3 4 2 3 4 1 3 4 1 2 ....

一一对应组合

(1,1)(2,2)(3,3)(4,4)(1,2)....

选择 k 个即可。

代码

#include <bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 10;

int x[N],y[N],vis[310][310],r[310],c[310];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        memset(r,0,sizeof(r));
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n*n;i++) x[i]=(i-1)%n+1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                y[(i-1)*n+j]=(i+j-2)%n+1;
            }
        }
        for(int i=1;i<=k;i++){
            vis[x[i]][y[i]]=1;
            r[x[i]]++,c[y[i]]++;
        }
        int ans=0;
        int minn=inf,maxn=-1;
        for(int i=1;i<=n;i++){
            minn=min(minn,r[i]);
            maxn=max(maxn,r[i]);
        }
        ans+=(maxn-minn)*(maxn-minn);
        minn=inf,maxn=-1;
        for(int i=1;i<=n;i++){
            minn=min(minn,c[i]);
            maxn=max(maxn,c[i]);
        }
        ans+=(maxn-minn)*(maxn-minn);
        printf("%d\n",ans);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                printf("%d",vis[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

E2.

题意

小明有 x 个糖果,有 n 个敌人,第 i 个敌人有 \(a_i\) 颗糖果,小明现在要和敌人通过糖果战斗。

规则为:如果小明的糖果数量大于等于当前敌人的糖果数量,那么小明胜利,赢得一个糖果。

小明可以生成一个 n 的全排列,然后将敌人按照此排列一次战斗。

现在给出 n 个敌人拥有的糖果数量,并给定一个小于等于 n 的素数 p ,问 x 的值可以是多少,当 小明有 x 个糖果的时候,假设有 \(f(x)\) 种排列方式使得小明可以赢过所有敌人,统计 \(f(x)\%p !=0\)的 x 的个数。

思路

这题我是抱着莽的心态过掉的。。。

首先大致确定 x 的取值范围,\(x >= min(a_i)\) ,另外小明胜利一次只会获得一次糖果,所以 x >= \(max(a_i)-n+1\)

然后再看当 x 的值确定的时候,全排列的方式有几种?

当 x 的值确定了,那么和第 i 个人战斗时的糖果数量也就确定了:

x x+1 x+2 x+3 x+4 x+5 ... x+n-1

那么对于 a 数组的全排列要使得第 i 个值,小于等于 \(x+i\)

首先将 a 数组按照升序排序。

对于\(a_i\) 它可以放的第一个位置为 \(a_i-x+1_{最小取1}\) ,可以放的位置有\(g(a_i)\) =\(i-(a_i-x+1)+1= x-a_i+i\)个。

对于每个 i 都求一遍,就我找的几个样例来说,\(g(a_i)\)相乘就是答案。因为 %的是一个质数 p ,所以只需要判断是否存在

\(g(a_i)\) >=p 即可。

可以看出 x 越大,\(g(a_i)\)越大,那么应该存在一个分界线,当 x < 分界线的时候可以,否则不可以。

二分检验一下,找到这个分界线,wa了。。。

然后看错误样例发现好像开始的一部分也存在不合法的,所以在求完结尾之后,再二分一个开头。
就过了

代码

#include <bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 10;

int arr[N],p,n;
int check(int x){
    for(int i=n;i;i--){
        int pre=arr[i]-x+1;
        if(pre<=0) pre=1;
        if((i-pre+1)%p==0) return 0;
    }
    return 1;
}
int main()
{
    scanf("%d%d",&n,&p);
    int maxn=-1,minn=inf;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&arr[i]);
        maxn=max(maxn,arr[i]);
        minn=min(minn,arr[i]);
    }
    sort(arr+1,arr+1+n);
    int l=max(minn,maxn-n+1),r=maxn-1;
    int en=-1;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            en=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    int aga=-1;
    l=max(minn,maxn-n+1),r=en;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            aga=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    if(en==-1){
        printf("0\n");
        return 0;
    }
    printf("%d\n",en-aga+1);
    for(int i=aga;i<=en;i++){
        printf("%d ",i);
    }
    printf("\n");
    return 0;
}
posted @ 2020-07-22 17:15  Valk3  阅读(76)  评论(0编辑  收藏  举报