【CF-1371 C-E2】
Codeforces Round #654 (Div. 2)
C.
题意
有 a 个香草饼干和 b 个巧克力饼干,以及两种类型的客人:
- 如果香草饼干的数量 > 巧克力饼干的数量,那么他会吃掉香草饼干,否则会吃掉巧克力饼干
- 如果巧克力饼干的数量 < 香草饼干的数量,那么他会吃掉巧克力饼干,否则会吃掉香草饼干
有 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 的个数为 k 。
- 矩阵中 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;
}