Codeforces Round 919 (Div. 2)

A. Satisfying Constraints

  • 贪心
  1. k ≥ x k \geq x kx,只需大于最大的 x x x即可满足要求
  2. k ≤ x k \leq x kx,只需小于最小的 x x x即可满足要求
  3. k ≠ x k \neq x k=x,将所有的 x x x用set记录下来,在范围内排除 x x x即可

AC代码

#include<iostream>
#include<set>
using namespace std;
long long read(){
	long long x=0,w=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')w=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=(x<<1)+(x<<3)+(c&15);
		c=getchar();
	}
	return x*w;
}

int main(){
	int t=read();
	while(t--){
		int n=read();
		int one=0,two=0x3f3f3f3f;
		set<int>three;
		while(n--){
			int a=read(),x=read();
			if(a==1)one=max(x,one);
			else if(a==2)two=min(x,two);
			else three.insert(x);
		}
		int ans=two-one+1;
		for(int i:three)if(one<=i&&i<=two)ans--;
		cout<<max(0,ans)<<endl;
	}
}

B. Summation Game

  • 博弈

由于所有数均为正整数,所以Alice和Bob的操作必定使得总和变小。首先对数组从大到小排序,设前 x x x个数的前缀和为 s u m x sum_x sumx

  1. Bob需要结果尽可能小,则Bob选取前 x x x个最大的数将其变为负数,则总和减小 2 s u m x 2sum_x 2sumx
  2. Alice需要结果尽可能大,但Alice删除 a i a_i ai将导致总和减小 a i a_i ai
    易知:若Alice先删除了不会被Bob操作的数将会导致总和更小,所以Alice删除的数必定是Bob操作的数。需注意并不是前 x x x个数,因为Bob的操作会因为Alice的操作而发生改变。
  3. Alice若删除了Bob本应操作的数,Bob的操作则会顺延到第 x x x个数之后,则Alice需要保证删除的第 i i i个数 a i > 2 a x + i a_i>2a_{x+i} ai>2ax+i,即 s u m n − a i − 2 a x + 1 > s u m n − 2 a i sum_n-a_i-2a_{x+1}>sum_n-2a_i sumnai2ax+1>sumn2ai ,Alice删除 a i a_i ai及Bob将 a x + i a_{x+i} ax+i取负的值应小于Bob将 a i a_i ai取负的值。
  4. 由于数组已预先排好序,则 a j ≥ a j + 1 a_j\geq a_{j+1} ajaj+1,若 a j + 1 > 2 a x + i a_{j+1}>2a_{x+i} aj+1>2ax+i,则有 a j > 2 a x + i a_{j}>2a_{x+i} aj>2ax+i,所以只需从左到右遍历Alice可能操作的前 k k k个数即可得出答案。

AC代码

#include<bits/stdc++.h>
using namespace std;
long long read(){
	long long x=0,w=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')w=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=(x<<1)+(x<<3)+(c&15);
		c=getchar();
	}
	return x*w;
}

int main(){
	int t=read();
	while(t--){
		int n=read(),k=read(),x=read();
		int a[n+1];
		long long sum[n+1];
		sum[0]=0;
		for(int i=1;i<=n;++i)a[i]=read();
		sort(a+1,a+n+1,greater<>());
		for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i];
		long long cut=sum[x]<<1;
		long long ans=sum[n]-cut;
		for(int i=1;i<=k;++i){
			cut=(sum[min(n,x+i)]-sum[i])<<1;
			ans=max(ans,sum[n]-sum[i]-cut);
		}
		cout<<ans<<endl;
	}
}

C. Partitioning the Array

  • 数论

对于任意可能的 k k k,每组数组中相同位置的数取模需相同,即 a i m o d    m ≡ a i + k m o d    m a_i\mod m\equiv a_{i+k}\mod m aimodmai+kmodm ,可转化为 ∣ a i − a i + k ∣ ≡ 0 m o d    m |a_i-a_{i+k}|\equiv0\mod m aiai+k0modm

由于 m > 1 m>1 m>1,所以对于任意k,需要遍历数组确定 m > 1 m>1 m>1

特别地,当 m = 0 m=0 m=0时,代表不存在元素 a 1 + k a_{1+k} a1+k,即只有一个数组,故 m m m可以取任何值。

AC代码

#include<bits/stdc++.h>
using namespace std;
long long read(){
	long long x=0,w=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')w=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=(x<<1)+(x<<3)+(c&15);
		c=getchar();
	}
	return x*w;
}
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}

int main(){
	int t=read();
	while(t--){
		int n=read();
		int a[n];
		for(int i=0;i<n;++i)a[i]=read();
		int ans=0;
		for(int i=1;i<=n;++i){
			if(n%i==0){
				int g=0;
				for(int j=i;j<n;++j){
					g=gcd(g,abs(a[j]-a[j-i]));
				}
				ans+=(g!=1);
			}
		}
		cout<<ans<<endl;
	}
}
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值