zoukankan      html  css  js  c++  java
  • 洛谷 P5061 秘密任务 —— 二分图

    题目:https://www.luogu.org/problemnew/show/P5061

    首先,“配合默契”就是连边的意思;

    但发现答案不好统计,因为有连边的两个点可以分在一组,也可以不分在一组;

    于是正难则反,因为没有连边的两个点一定不在一组,所以连成补图,二分图染色;

    如果染色出现矛盾,就是无解——第三问的意思是什么?无解的时候应该也只是某几个连通块染色不合法,在其它连通块中也有配合默契的一对人可以分在同一组啊,为什么输出 m ?

    然后背包一下,得到可以选择的人数,直接一个一个加到答案即可,差值最小就是人数最接近 n/2;

    然后配合默契的一对人不能在一组的方案数也直接 n^2 统计在一个连通块没有连边但染色不同的点对即可;

    虽然出题人的正解并不是二分图,但不太懂那个正解...

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=2505,mod=1e9+7;
    int n,m,col[xn],f[xn],cnt,s[xn][3],in[xn],tot;
    bool sid[xn][xn],cant[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    ll pw(ll a,int b)
    {
      ll ret=1;
      for(;b;b>>=1,a=(a*a)%mod)if(b&1)ret=(ret*a)%mod;
      return ret;
    }
    int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;}
    bool dfs(int x,int cr,int nw)
    {
      col[x]=cr; s[nw][cr]++; in[x]=nw;
      for(int u=1;u<=n;u++)
        {
          if(sid[x][u]||x==u)continue;
          if(!col[u])dfs(u,3-cr,nw);
          else if(col[u]==col[x])return 0;
        }
      return 1;
    }
    int main()
    {
      n=rd(); m=rd();
      for(int i=1,x,y;i<=m;i++)x=rd(),y=rd(),sid[x][y]=sid[y][x]=1;
      bool flag=0;
      for(int i=1;i<=n;i++)
        if(!col[i])
          {
        bool fl=dfs(i,1,++cnt);
        if(!fl)flag=1,cant[cnt]=1;
          }
      if(flag){puts("-1"); printf("%d
    ",m); return 0;}//m?!
      else
        {
          f[0]=1;
          for(int i=1;i<=cnt;i++)
        for(int j=n;j>=0;j--)//--!
          {
            if(j>=s[i][1])f[j]|=f[j-s[i][1]];
            if(j>=s[i][2])f[j]|=f[j-s[i][2]];
          }
          int ans=0,num;
          for(int i=0;i<=n/2;i++)
        {
          if(!f[i]||!f[n-i])continue;//f[0]=1
          ans++; num=i;
        }
          printf("%d %d
    ",ans,upt(pw(2,n-num)-pw(2,num)));
        }
      int sum=0;
      for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
          if(in[i]==in[j]&&sid[i][j]&&(cant[in[i]]||col[i]!=col[j]))sum++;
      printf("%d
    ",sum);
      return 0;
    }
  • 相关阅读:
    【bzoj2724】[Violet 6]蒲公英 分块+STL-vector
    【bzoj4026】dC Loves Number Theory 可持久化线段树
    【bzoj3744】Gty的妹子序列 分块+树状数组+主席树
    【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set
    【bzoj3060】[Poi2012]Tour de Byteotia 并查集
    【bzoj3510】首都 LCT维护子树信息(+启发式合并)
    【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
    【bzoj3261】最大异或和 可持久化Trie树
    【bzoj2081】[Poi2010]Beads Hash
    【bzoj4260】Codechef REBXOR Trie树
  • 原文地址:https://www.cnblogs.com/Zinn/p/10081579.html
Copyright © 2011-2022 走看看