Codeforces Round #680 (Div. 2, based on Moscow Team Olympiad) A-D

感想

我觉得本场的A-D除了C都是猜结论题,发现数据的规律固然是好事,但也需要弄清楚为什么是这样的,所以接下来我将尽可能详细地讲解一些证明的过程

A

https://codeforces.com/contest/1445/problem/A
给定长度为n的两个数组a和b,问是否存在某种排列方式,使得\(a_{i}+b_{i}<=x\)总是成立的。
容易发现本题的要求是将\(a_{i}+b_{i}\)的最大值最小化,问这个最小值是否总是<=x的

我们首先把a和b从小到大排序,当考虑给\(a_{n}\)配对一个什么样的b值时,应该想到如果给它配上b[2...n]时,那么\(a_{n}+b_{i}<=a_{i}+b_{1}(i<n)\)恒成立,这样没有做到让最大值最小,所以应该给\(a_{n}\)配上\(b_{1}\),以此类推,给\(a_{i}\)配上\(b_{n+1-i}\)

#include<bits/stdc++.h>    
#define ll long long      
using namespace std;
const int N = 100005,M = 100005;
int n,m,t;
int x;
int a[55],b[55];

int main(){
	cin>>t;
	while(t--){
		cin>>n>>x;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			cin>>b[i];
		}
		sort(a+1,a+n+1);
		sort(b+1,b+n+1,greater<int>());
		bool f=1;
		for(int i=1;i<=n;i++){
			if(a[i]+b[i]>x){
				f=0;
				break;
			}
		}
		if(f) puts("YES");
		else puts("NO");
	}
	return 0;
}

B

https://codeforces.com/contest/1445/problem/B
简化题意:有两场比赛,第一场比赛排名前100的选手 第一场比赛的分数>=a, 第二场比赛的分数>=b;第二场比赛排名前100的选手 第二场比赛的分数>=c, 第一场比赛的分数>=d
问(总分为第一场分数+第二场)总分排在第100名的选手可能的最小分数是多少

首先可以论断,第一场比赛分数>=a,第二场比赛分数>=b的人数必然>=100,否则第一场比赛排名前100的选手的最低分不会是a和b,而是s1<a or s2<b的分数
同理第一场比赛分数>=d,第二场比赛分数>=c的人数必然>=100
所以总分为a+b的选手至少有100个,总分为c+d的选手也至少有100个
所以排名第100的选手的分数为max(a+b,c+d)

#include<bits/stdc++.h>    
#define ll long long      
using namespace std;
const int N = 100005,M = 100005;
int n,m,t;
int x;
int a,b,c,d;

int main(){
	cin>>t;
	while(t--){
		cin>>a>>b>>c>>d;
		cout<<max(a+b,c+d)<<endl; 
	}
	return 0;
}

C

https://codeforces.com/contest/1445/problem/C
每次给你两个数p和q (\(p\leq 10^{18},q\leq 10^{9}\)),需要找到最大的满足(p%x==0&&x%q!=0)的x

如果p%q不为0,那么x取p最大
因为这道题肯定和质因数分解有关,于是可以先将p和q做质数的唯一分解(先不考虑时间复杂度),我们发现:p肯定有q中所有的质因子,而且质因子的次数还比q中的多(这是p%q==0的原因),那么如果将p中质因子的次数减少到比q中的质因子次数少1,这样减少的最少,而且p肯定不能再整除q了
一个写法上的小tips:先找出1e4.5内的所有质数,再对q做分解,再用当前质数分解p,这样时间复杂度是可以接受的
另一个坑点:如果q是一个很大的质数,那么就用p不断除以q(直到不能再除),剩下的就是答案

#include<bits/stdc++.h>    
#define ll long long      
using namespace std;
int n,m,t;
ll p,q;
int cntq[100005],cntp[100005];
ll prime[20005];
bool vis[100005];
int cnt;

void init(int N){
	for(int i=2;i<=N;i++){
		if(vis[i]) continue;
		prime[++cnt]=i;
		for(int j=i;j<=N;j+=i){
			vis[j]=1;
		}
	}
}

bool isprime(int x){
	if(x<4) return 1;
	for(int i=2;i*i<=x;i++){
		if(x%i==0) return 0;
	}
	return 1;
}

int main(){
	init(1e5);
	cin>>t;
	while(t--){
		cin>>p>>q;
		ll pp=p;
		if(p%q){
			cout<<p<<endl;
			continue;
		}
		//1.�ֽ�q,�õ��������Ӽ����� 
		//2.���p�� q�е������Ӹ�������ij��������ʹ��cnt_x_p->cnt_x_q-1������С�� 
		
		if(isprime(q)){
			while(p%q==0) p/=q;
			cout<<p<<endl;
			continue;
		} 
		
		memset(cntq,0,sizeof(cntq));
		memset(cntp,0,sizeof(cntp));
		ll ans=1e18+10;
		for(int i=1;i<=cnt;i++){
			if(q<prime[i]) break;
			if(q%prime[i]==0){
				while(q%prime[i]==0){
					q/=prime[i];
					cntq[prime[i]]++;
				}
				while(p%prime[i]==0){
					p/=prime[i];
					cntp[prime[i]]++;
				}
				ll tem=1;
				for(int j=1;j<=cntp[prime[i]]-cntq[prime[i]]+1;j++) tem*=prime[i];
				ans=min(ans,tem);
			}
		}
		cout<<pp/ans<<endl;
	}
	return 0;
}

D

https://codeforces.com/problemset/problem/1445/D
容易观察到ans=\(C_{2n}^{n}*sum\) (这里的sum是对任意排列求出的cost
那么到底为什么是这样的呢

from toturial:先把a排序,令L=a[1...n],R=a[n+1...2n]
任意形成的序列
p 满足 有i个来自L,n-i个来自R(从小到大)
q 满足 有i个来自R,n-i个来自L(从大到小)
sum=\(\sum_{i=1}^{n}\)a[i+n]-a[i] 对于i\(\in\)[1...n]恒成立

#include<bits/stdc++.h>    
#define ll long long      
using namespace std;
const int N = 300005;
const ll mod = 998244353;
int n,m,t;
ll fac[N],inv[N];
int a[N],b[N];

ll qpow(ll a,ll x){  //����Ҳ��ll  ��Ϊ������inv[] 
	ll ans=1;
	while(x){
		if(x&1){
			ans*=a;	
			ans%=mod;
		}
		a*=a;
		a%=mod;
		x/=2;
	}
	return ans;
}

void init(int N){
	fac[0]=1;inv[0]=1;
	for(int i=1;i<=N;i++){
		fac[i]=fac[i-1]*i%mod;
	}
	inv[N]=qpow(fac[N],mod-2);  //n����Ԫ   ��1/(n+1)! (mod p) 
	for(int i=N-1;i>=1;i--){
		inv[i]=inv[i+1]*(i+1)%mod;  // 1/n!=1/(n+1)! * (n+1) %p
	}
}

ll C(int n,int m){
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main(){
	init(300005);
	cin>>n;
	for(int i=1;i<=2*n;i++)scanf("%d",&a[i]);
	sort(a+1,a+2*n+1);
	for(int j=n+1;j<=2*n;j++) b[j-n]=a[j];
	sort(b+1,b+n+1,less<int>());
	ll sum=0;
	for(int i=1;i<=n;i++){
		sum=sum+1ll*abs(b[i]-a[i]);
		sum%=mod;
	}
	cout<<C(2*n,n)%mod*sum%mod<<endl;
	return 0;
}
posted @ 2022-03-18 11:32  starlightlmy  阅读(43)  评论(0)    收藏  举报