A - Array Rearrangment
思路:正排序a,逆排序b,找ai+bi是否大于某个值
B - Elimination
题面:
a表示第一场前100最低分,c表示第二场前100最低分
b表示第一场前100的某个人在第二场的最低分
d表示第二场前100的某个人在第一场的最低分
求两场成绩第100名最小值分数
思路:max(a+b,c+d)
C - Division
题面:输入q(小于1e18),p(小于1e9),求q的最大因子 % p !=0
思路:
1.q % p !=0直接输出 q
2.因为q太大了,求质因子要特殊方法(比如Pollard_rho),所以我们去判断 p 的质因子,如果q没有这个属于p的质因子,那么他就是备胎之一,如果有把q除到没有这个质因子,也变成了备胎之一。
最后把最大的备胎找到就行了
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define lson(x) x<<1
#define rson(x) x<<1|1
using namespace std;
const int N=1e5+10;
ll p;
int q;
int a[100],num[100],cnt;
void prime(int x){
int k=sqrt(x);
for(int i=2;i<=k;i++){
if(x%i==0){
a[cnt]=i;
int nu=0;
while(x%i==0){
nu++;x/=i;
}
num[cnt++]=nu;
}
}
if(x!=1){
num[cnt]=1;a[cnt++]=x;
}
return ;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%lld%d",&p,&q);
cnt=0;
if(p%q!=0){
printf("%lld
",p);continue;
}
prime(q);
ll ans=1;
for(int i=0;i<cnt;i++){
ll zhi=1;//cout<<a[i]<<num[i]<<endl;
for(int j=1;p%zhi==0;j++){
zhi*=(ll)a[i];
if(p%zhi==0 && (p/zhi)%(ll)q!=0){
ans=max(ans,p/zhi);
}
}
}
printf("%lld
",ans);
}
return 0;
}
/*
*/
D - Divide and Sum
题面:吐槽,这个题面,一开始以为是子串,后面看了样例解释是随便选n个
给2*n的序列,你要把他分成两份n序列(x[],y[]),第一份从小到大排列,第二份从大到小排列,求每种分法的|xi-yi|之和,取模
思路:
分法很好想,排列组合C(n,2 * n)即可,但是|xi-yi|一开始没有任何思路,然后我枚举了一下1 2 3 4
选1 2 | 3 4 最后得4
选1 3 | 2 4 最后得4
选1 4 | 2 3 最后得4
啊这,然后就是一个前缀和的问题了,从小到大排序前n个减,后n个加 * C(n,2 * n)。【上述结论,数学菜鸡无法解答。。。然后排列组合那里需要逆元】
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define lson(x) x<<1
#define rson(x) x<<1|1
#define mod 998244353
using namespace std;
const int N=3e5+10;
int n;
int a[N];
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1){
ans*=a;ans%=mod;
}
a*=a;a%=mod;
b>>=1;
}
return ans;
}
ll C(ll a,ll b){
ll ans=1;
for(ll i=a;i>b;i--){
ans*=i;ans%=mod;
}
for(ll i=b;i>=1;i--){
ans*=ksm(i,mod-2);ans%=mod;
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=0;i<2*n;i++){
scanf("%d",&a[i]);
}
sort(a,a+2*n);
ll sum1=0,sum2=0;
for(int i=0;i<n;i++){
sum1+=(ll)a[i];
}
for(int i=n;i<2*n;i++){
sum2+=(ll)a[i];
}
ll ans=(sum2-sum1)%mod;
printf("%lld
",ans*C((ll)2*n,(ll)n)%mod);
return 0;
}
/*
*/
E - Team-Building
好题!用一下午时间让我知道了,可撤回并查集别顺手写路径压缩,wa了n次
无向图并查集判奇数环思路
判断F(u)等不等于F(v),等于就是有奇数环
不等于就这样并
mere(u,v+n)
mere(u+n,v)
可撤回并查集(请勿路径压缩)模板
int F(int x){return f[x]==x?x:F(f[x]);}//如果这题wa29,可以注意一下不要路径压缩
void mere(int x,int y){
int xx=F(x),yy=F(y);
if(xx!=yy){
if(sz[xx]>sz[yy])swap(xx,yy);
sz[yy]+=sz[xx];
f[xx]=f[yy];
ne[++tot]=xx;
}
}
void roll_back(int l){
while(tot>l){
int now=ne[tot--];
sz[f[now]]-=sz[now];
f[now]=now;
}
}
题面:有n个点,m条边,k种颜色,n个点有不同颜色,求有多少两种颜色构成的图无奇数环,数据5e5
思路:有k种颜色,所以有k * (k-1)/2的可能,正着加法做肯定tle,所以我们去做减法
如果并查集同种颜色的边并起来,有奇数环k-1,但要将单色图并好,不同颜色的边存起来,排序。找不同颜色边(出现相同两种颜色)的个数,然后判断是否有奇数环,如果有答案-1,然后撤回并查集。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e6+10;
int f[N],a[N],ne[N],sz[N],n,tot,m,vis[N];
ll k;
struct node{
int nu,nv,u,v;
friend bool operator<(const node a,const node b){
if(a.nv==b.nv){
return a.nu<b.nu;
}
return a.nv<b.nv;
}
}p[N];
void inint(){
for(int i=1;i<=2*n;i++){f[i]=i;sz[i]=1;}
tot=0;
}
int F(int x){return f[x]==x?x:F(f[x]);}//如果这题wa29,可以注意一下不要路径压缩
void mere(int x,int y){
int xx=F(x),yy=F(y);
if(xx!=yy){
if(sz[xx]>sz[yy])swap(xx,yy);
sz[yy]+=sz[xx];
f[xx]=f[yy];
ne[++tot]=xx;
}
}
void roll_back(int l){
while(tot>l){
int now=ne[tot--];
sz[f[now]]-=sz[now];
f[now]=now;
}
}
int main(){
scanf("%d%d%lld",&n,&m,&k);
inint();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
ll tmp=k;
int cnt=0;
for(int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
if(a[u]==a[v]){
if(!vis[a[u]] &&F(u)==F(v)){
tmp--;vis[a[u]]=1;//相同颜色的集合里有奇数环,直接颜色种类-1
continue;
}
mere(u,v+n);
mere(u+n,v);
}
else{
if(a[u]>a[v])swap(u,v);//把颜色从小到大存入,方便排序找相同的两个颜色的图
p[++cnt].u=u,p[cnt].v=v;p[cnt].nu=a[u];p[cnt].nv=a[v];
}
}
ll ans=(tmp-1)*tmp/2;//cout<<ans<<endl;
sort(p+1,p+cnt+1);
int i,j;
int Len=tot;//现在所有的颜色相同的点并在同一个集合里,每次两个不同颜色点相连之后撤回到Len的地方
for(i=1;i<=cnt;i=j+1){
roll_back(Len);//撤回到原来颜色相同的点并在同一个集合的位置
for(j=i;j<cnt;){
if(p[j].nu!=p[j+1].nu || p[j].nv!=p[j+1].nv){break;}
j++;
}
if(vis[p[j].nu] || vis[p[j].nv]){continue;}
for(int kk=i;kk<=j;kk++){
if(F(p[kk].u)==F(p[kk].v)){ans--;break;}
mere(p[kk].u,p[kk].v+n);
mere(p[kk].u+n,p[kk].v);
}
}
printf("%lld
",ans);
return 0;
}