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;
}

浙公网安备 33010602011771号