zoukankan      html  css  js  c++  java
  • 【NOI OL #1】序列

    题目链接

    首先我们发现,各个位置之间,$a$和$b$的原数值并不重要,所以我们可以令$b_ileftarrow b_i-a_i$,接下来只使用这个差值。

    然后我们发现,2操作是可以使两个位置之间的差值进行“流动”。

    所以,如果只有2操作,把每个位置看成点,差值是点权,那么2操作就是随意转运权值的无向边,2操作构成的连通块的点权能够全部变为$0$等价于点权和为$0$。

    然后加入1操作,发现它可以使相邻的两个点的点权和增减$2$的倍数。

    然后我们只会做2操作。

    这里是个我的思维瓶颈,考试的时候没突破,人裂开。

    这时候就体现了手玩数据的好处了。我一直没这个习惯,导致有些挺显然的结论看不出来。

    然后可以发现,1操作构成的路径(不一定是简单路径)上,距离为奇数的两个点可以同增同减,距离为偶数的两个点可以转运权值。

    思考一下,如果只有1操作,那么这个路径的性质就迫使我们进行染色。染色……二分图来了。

    如果某个连通块是个二分图,或者说,没有奇环,那么只要两个分图的权值和相同,就可以对消了。

    那有奇环呢?发现每条路径只需要绕一下这个奇环,就可以改变自身的奇偶性,那就是都可以随意转运权值,要连通块权值和为$0$咯?也不全对,因为我们还可以利用奇数长度路径的性质,对整个连通块的点权和增减$2$的倍数。也就是说只要连通块点权和是偶数,就可以使每个点的点权变为$0$。

    然后考虑怎么联合两种操作。

    我们发现2操作连出来的连通块,内部的权值是可以随意转运的,那么对于一条1边(1操作连出来的边),固定了一个端点,另一个端点连在某个2边连通图里,不论连哪个点都是等价的。那么我们可以对2边连通块进行缩点,然后1边就只连2边连通块就行了。如果出现1边连了同一个2边连通块,直接当做奇环就可以了。

    讲完了。嗯。记得开long long,然后常数写好一点。

    我交过一份95分的代码,超时一个点。然后删了一句数组初始化为$0$的memset就卡过了。

    代码(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    typedef long long LL;
    typedef unsigned int UI;
    const int N=1e5;
    
        int T,n,m;
        LL a[N+3];
        int k[3],u[3][N+3],v[3][N+3];
        vector<int>g[N+3];
        bool flag;
        int cnt,bel[N+3];
        LL sum[N+3];
        
    void dfs1(int u){
        for(UI i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(bel[v]!=0)
                continue;
            
            bel[v]=bel[u];
            sum[bel[u]]+=a[v];
            dfs1(v);
            
        }
        
    }
        
    IL void sol1(){
        for(int i=1;i<=k[2];i++){
            g[u[2][i]].push_back(v[2][i]);
            g[v[2][i]].push_back(u[2][i]);
            
        }
        
        memset(bel,0,(n+3)*(sizeof(int)));
        cnt=0;
        for(int i=1;i<=n;i++)
        if(bel[i]==0){
            bel[i]=++cnt;    sum[cnt]=a[i];
            dfs1(i);
            
        }
        
        flag=true;
        for(int i=1;i<=cnt&&flag;i++)
        if(sum[i]!=0)
            flag=false;
        if(flag)
            printf("YES
    ");
        
    }
    
        bool tag[N+3],ex;
        int col[N+3];
        LL s[3];
        
    void dfs2(int u){
        for(UI i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(col[v]!=0){
                if(col[u]==col[v])
                    ex=true;
                continue;
                
            }
            
            col[v]=3-col[u];
            if(tag[v])ex=true;
            s[col[v]]+=sum[v];
            dfs2(v);
            
        }
        
    }
    
    IL void sol2(){
        memset(tag,0,(cnt+3)*(sizeof(int)));
        for(int i=1;i<=cnt;i++)
            g[i].clear();
        
        for(int i=1;i<=k[1];i++)
        if(bel[u[1][i]]==bel[v[1][i]])
            tag[bel[u[1][i]]]=true;
        else {
            g[bel[u[1][i]]].push_back(bel[v[1][i]]);
            g[bel[v[1][i]]].push_back(bel[u[1][i]]);
        }
        
        memset(col,0,(cnt+3)*(sizeof(int)));
        flag=true;
        for(int i=1;i<=cnt;i++)
        if(col[i]==0){
            ex=tag[i];    s[2]=0;
            col[i]=1;    s[1]=sum[i];
            dfs2(i);
            if(ex)
                flag&=((s[1]+s[2])&1)==0;
            else 
                flag&=s[1]==s[2];
            
        }
        
        if(flag)
            printf("YES
    ");
        else 
            printf("NO
    ");
        
    }
        
    IL void sol(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++){
            LL x;    scanf("%lld",&x);
            a[i]=x-a[i];
            g[i].clear();
        }
        memset(g,0,sizeof g);
        k[1]=k[2]=0;
        for(int i=1;i<=m;i++){
            int t;
            scanf("%d",&t);
            k[t]++;
            scanf("%d%d",&u[t][k[t]],&v[t][k[t]]);
            
        }
        
        flag=false;
        sol1();
        if(flag)return ;
        sol2();
        
    }
    
    int main(){
        scanf("%d",&T);
        while(T--)
            sol();
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    TensorFlow Executor解析
    面试复习
    [洛谷]P1880 石子合并问题
    [西建大ACM协会]OJ平台如何使用
    [ACM] 相关OJ及在线运行代码网站
    [MySQL] Win10 安装MySQL5.7.27
    [PTA] PAT(A) 1012 The Best Rank (25 分)
    [PTA] PAT(A) 1011 World Cup Betting (20 分)
    [PTA] PAT(A) 1010 Radix (25 分)
    [PTA] PAT(A) 1009 Product of Polynomials (25 分)
  • 原文地址:https://www.cnblogs.com/Hansue/p/12985497.html
Copyright © 2011-2022 走看看