bzoj 2169 连边——去重的思想

Posted narh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2169 连边——去重的思想相关的知识,希望对你有一定的参考价值。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2169

如果之前都去好重了,可以看作这次连的边只会和上一次连的边重复。

可以认为从上上次的状态到这次的状态,转移的过程对于上上次的每个状态来说都是把剩余位置所有连边的可能性遍历了恰好一遍!即,当前连了 i 条边,与上次连的边重复的数量就是 C(n,2)-(i-2)(n个点里选2个是一共有多少空位放边,上上次已经放了 i-2 条,这次与上次可以重复的位置有该式那么多个)。

关于同种方案因为连边顺序不同导致的重复计数,只要每次算好一条边之后除以 i 即可;意即对每一种方案,这次放的边可以在已经放的 i 条边中的任意一条,导致重复。不这样去重而最后除以所填边数的阶乘是不行的,因为自己的转移在由有重复的状态转移来的时候不成立。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1005,mod=10007;
int n,m,t,dp[N][N];
bool deg[N];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>9||ch<0){if(ch==-)fx=0;ch=getchar();}
  while(ch>=0&&ch<=9) ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
  return fx?ret:-ret;
}
int calc(int a){return (a*(a-1)>>1)%mod;}
int pw(int x,int k)
{
  int ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
int main()
{
  n=rdn(); m=rdn(); t=rdn();
  for(int i=1,u,v;i<=m;i++)
    {
      u=rdn(); v=rdn();
      deg[u]=!deg[u]; deg[v]=!deg[v];
    }
  int cnt=0;
  for(int i=1;i<=n;i++) cnt+=deg[i];
  dp[0][cnt]=1;
  for(int i=1;i<=t;i++)
    {
      int d=pw(i,mod-2);
      for(int j=0;j<=n;j++)
    {
      dp[i][j]=dp[i-1][j]*j%mod*(n-j)%mod;
      dp[i][j]=(dp[i][j]+dp[i-1][j+2]*calc(j+2))%mod;
      if(j>=2)
          dp[i][j]=(dp[i][j]+dp[i-1][j-2]*calc(n-j+2))%mod;
      if(i>1)dp[i][j]-=dp[i-2][j]*(calc(n)-(i-2))%mod;
      if(dp[i][j]<0)dp[i][j]+=mod;
      dp[i][j]=dp[i][j]*d%mod;
    }
    }
  printf("%d
",dp[t][0]%mod);
  return 0;
}

 

以上是关于bzoj 2169 连边——去重的思想的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2169: 连边

[BZOJ 2169]连边

[BZOJ 2169]连边

关于选择排序并去重的几种算法分析

刷题 | 数组去重的4种方法引发的思考

关于优雅去重的一些感想