A.Array Rearrangment:
题目链接:https://codeforces.ml/contest/1445/problem/A
题目大意:
给定n,x以及长度为n的两个序列a,b,要求对a,b重新排序后,使得对于任意的i有a[i]+b[i]≤x
成立
题目分析:
1.首先对a排序形成不下降序列,对b排序形成不上升序列。检查此时是否对于任意的i有a[i]+b[i]≤x
成立。成立输出YES,否则输出NO。
2.证明此时是所有a[i]+b[i]
的最大值最小的序列:
- 设排序后的a中有
a[i]≤a[j](i≤j)
,设排序后的b中有b[i]≥b[j](i≤j)
,形成的和为a[i]+b[i]
和a[j]+b[j]
,最大值为max(a[i]+b[i],a[j]+b[j])
- 交换
b[i]
,b[j]
,形成的和为a[i]+b[j]
和a[j]+b[i]
,最大值为max(a[i]+b[j],a[j]+b[i])
,显然此时的最大值大于原序列。证明完毕
正解程序:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const ll maxn=100;
ll a[maxn],b[maxn],x;
ll n,T;
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&x);
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++)
scanf("%lld",&b[i]);
ll flag=0;
for(ll i=1;i<=n;i++)
{
if(a[i]+b[n-i+1]>x)
{
flag=1;
break;
}
}
if(flag==0)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
B.Elimination:
题目链接:https://codeforces.ml/contest/1445/problem/B
题目大意:
一个比赛有两场分比赛,每场比赛按照分数从高到低排名,分数相同时按照序号排序,每个榜单只有前100人。两场比赛后给出一个总排名,总排名按照两场比赛得分和进行从高到低排名,现在总榜丢失,只有前两场比赛的榜单,现在知道第一场的第一百名得a分,且第一场前100名在第二场至少获得b分。第二场的第100名获得c分,且第二场前100名在第一场都至少获得d分,现在问总榜的第100名最少是多少分。
题目分析:
根据题意,那么我们可以得知我们至少有100人获得a+b
分,至少100人获得c+d
分,所以排下来第100名的最小值就是max(a+b,c+d)
。
正解代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
ll T;
int main()
{
scanf("%lld",&T);
while(T--)
{
ll a,b,c,d;
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
printf("%lld\n",max(a+b,c+d));
}
return 0;
}
C. Division:
题目链接:https://codeforces.ml/contest/1445/problem/C
题目大意:
有t组测试数据,每组给出了p和q ,要求找出最大的x使得p能被x整除,且x不能被q整除。
题目分析:
1.首先我们发现如果p%q!=0
,则p就是答案,因为此时p%p==0 && p%q!=0
。满足条件,而大于p的数则不再能整除p。
2.因为此时p是q的倍数,所以q的质因数p一定有,所以我们分别将p,q分解质因数,得到p=a1k1 * a2k2 ······ ankn,q=a1b1 * a2b2 ······ ankn。(k1 ~ kn大于0,b1 ~ bn大于等于0)
3.因为满足条件的x一定是p的因数,且不能是q的倍数。所以最大的值就是q中所有质因数的幂变得和p中对应数的幂相同,选择其中一个数使得它的幂是p中对应数幂减一。例如:
p=a1k1 * a2k2 * a3k3(k1 ~ k3大于0)
q=a1b1 * a2b2 * a3b3(b1 ~ b3大于等于0)
则x=max(a1k1-1 * a2k2 * a3k3,a1k1 * a2k2-1 * a3k3,a1k1 * a2k2 * a3k3-1)
正解代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const ll maxn=40010;
ll T,prime[maxn],count1=0;
bool vis[maxn];
ll act[maxn],pos=0,now[maxn];
void oula()
{
memset(vis,false,sizeof(vis));
for(ll i=2;i<=maxn-10;i++)
{
if(!vis[i])
prime[++count1]=i;
for(ll j=1;j<=count1 && i*prime[j]<=maxn-10;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0)
break;
}
}
}
ll quickmi(ll a,ll p)
{
ll ans=1;
while(p)
{
if(p&1)
ans=ans*a;
a=a*a;
p>>=1;
}
return ans;
}
int main()
{
oula();
scanf("%lld",&T);
while(T--)
{
pos=0;
ll a,b;
scanf("%lld%lld",&a,&b);
if(a%b!=0)
printf("%lld\n",a);
else
{
for(ll i=1;i<=count1 && prime[i]<=b;i++)
{
if(b%prime[i]==0)
{
act[++pos]=prime[i];
now[pos]=1;
while(b%prime[i]==0)
{
b/=prime[i];
now[pos]*=prime[i];
}
}
}
if(b!=1)
{
act[++pos]=b;
now[pos]=b;
}
ll Min=1e18,used=a;
for(ll i=1;i<=pos;i++)
{
ll aim=0;
a/=now[i];
while(a%act[i]==0)
{
a/=act[i];
aim++;
}
Min=min(quickmi(act[i],aim+1),Min);
}
printf("%lld\n",used/Min);
}
}
return 0;
}
D. Divide and Sum:
题目链接:https://codeforces.ml/contest/1445/problem/D
题目大意:
现在有一个序列有 2n 个元素,让你分成两个元素为 n 的子序列 p 和 q,将两个序列一个从大到小排序,一个从小到大排序,排序后设 f ( p , q ) = ∑ i = 1 n ∣ p i − q i ∣ f(p,q)=\sum_{i=1}^{n}|p_{i}-q_{i}| f(p,q)=∑i=1n∣pi−qi∣,问所有可能的子序列对应的f(p,q)之和为多少,答案对998244353取模。
题目分析:
1.对原序列升序排序,我们所选的p,q序列可以有如下方式得到:
- 将原序列分为前后n个数组成的两个序列,称为序列1和序列2
- p即在序列1中选择x个,在序列2中选择n-x个
- q即在序列1中选择n-x个,在序列2中选择x个。
2.此时无论x是多少,所选的x个数是多少,
f
(
p
,
q
)
=
∑
i
=
1
n
∣
p
i
−
q
i
∣
f(p,q)=\sum_{i=1}^{n}|p_{i}-q_{i}|
f(p,q)=∑i=1n∣pi−qi∣=
∑
i
=
1
n
(
q
i
−
p
i
)
\sum_{i=1}^{n}(q_{i}-p_{i})
∑i=1n(qi−pi)=sum(定值)。所以最后的答案就是sum * C(2n,n)。
3.因为有取余运算,求组合数涉及除法,所以要使用乘法逆元,因为模数是质数,所以利用费马定理求出逆元即可。
正解程序:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long ll;
const ll maxn=300010;
const ll mod=998244353;
ll a[maxn],fac[maxn],n;
ll quickmi(ll a,ll p)
{
ll ans=1;
while(p)
{
if(p&1)
ans=ans*a%mod;
a=a*a%mod;
p>>=1;
}
return ans;
}
void init()
{
fac[0]=1;
for(ll i=1;i<=maxn-10;i++)
fac[i]=fac[i-1]*i%mod;
}
int main()
{
init();
scanf("%lld",&n);
for(ll i=1;i<=2*n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+2*n+1);
ll sum=0,fina=0;
for(ll i=1;i<=n;i++)
sum=(sum+a[i+n]-a[i])%mod;
ll temp=quickmi(fac[n],mod-2);
fina=sum*fac[2*n]%mod*temp%mod*temp%mod;
printf("%lld\n",fina);
return 0;
}