• Codeforces Round #680 (Div. 2 可撤销并查集)


    这场比赛

    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;
    }
    
    
  • 相关阅读:
    ORACLE各种对象、概念及关系整理(一文读懂)
    Spring面试题总结及答案
    MySQL面试总结
    可变参数,你还为方法的参数而烦恼吗?可变参数,让你的头发从此“茂密”!
    java编译报错: 找不到或无法加载主类 Demo.class 的解决方法
    java编译报错 错误: 编码GBK的不可映射字符
    sql server2017开启远程连接
    sql server一些快捷方式和操作技巧
    sql server无法连接本地服务器
    phpStorm+xdebug调试(php7.3)
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/13937590.html
Copyright © 2020-2023  润新知