P3513 [POI2011] KON-Conspiracy

题目描述:

Byteotia的领土被占领了,国王Byteasar正在打算组织秘密抵抗运动。国王需要选一些人来进行这场运动,而这些人被分为两部分:一部分成为同谋者活动在被占领区域,另一部分是后勤组织在未被占领的领土上运转。但是这里出现了一个问题:

  1. 后勤组织里的任意两人都必须是熟人,以促进合作和提高工作效率。
  2. 同谋者的团体中任意两人都不能是熟人。
  3. 每一部分都至少要有一个人。国王想知道有多少种分配方案满足以上条件,当然也有可能不存在合理方案。

求方案数。

数据范围:

\(2\le n\le 5000\)
\(0\le k_i\le n-1\)

思路:

首先假设我们发现题目中是所有点都被两个集合所包含!!千万不要像我一样一开始理解为可以不包含满……

然后我们考虑这个题目的一个性质:如果想要选出一个集合 \(A\) 使得集合 \(A\) 的所有点之间都有连边,且 \(A\) 在全集 \(U\) 中的补集之间两两没有连边,则其一定满足 \(Deg=S+\binom{m}{2}\),其中 \(Deg\) 表示这个集合所有点的度数之和,\(S\) 表示整张图的边数,\(m\) 表示这个集合的大小

然后对于任意的一个子集,一定满足 \(Deg\le S+\binom{m}{2}\)

所以如果固定了 \(m\) 为多少,则只需要判断度数最大的 \(m\) 个点就可以了。

如果这 \(m\) 个点合法,我们不妨将这 \(m\) 个点中度数最小的点替换成其他未选择的且度数与其相同的点,假设一共有 \(a\) 个度数为最小值的点,其中 \(m\) 个点中选择了 \(b\) 个,所以方案数为 \(\binom{a}{b}\)

虽然这道题可以使用 \(2-SAT\) 来解决,但是显然能有更简单的方式肯定还是选择用简单的方式完成。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5005;
const int mod=1e9+7;
int n;
int deg[maxn];
int fac[maxn],inv[maxn];
int qp(int x,int k){
    int res=1;
    while(k){
        if(k&1)res=res*x%mod;
        x=x*x%mod;
        k>>=1;
    }
    return res;
}
void init(){
    int N=maxn-5;
    fac[0]=1;
    for(int i=1;i<=N+1;i++)fac[i]=fac[i-1]*i%mod;
    inv[N+1]=qp(fac[N+1],mod-2);
    for(int i=N;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
int C(int n,int m){
    if(n<m||m<0)return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
signed main(){
    init();
    cin>>n;
    for(int i=1;i<=n;i++){
        int k;cin>>k;
        deg[i]+=k;
        while(k--){
            int x;cin>>x;
        }
    }
    int S=0;
    for(int i=1;i<=n;i++)S+=deg[i];
    S/=2;
    sort(deg+1,deg+n+1,greater<int>());
    int sum=0,ans=0;
    for(int i=1;i<=n;i++){
        sum+=deg[i];
        if(sum==S+i*(i-1)/2){
            int a=0,b=0;
            int pos=i;
            while(pos>=1&&deg[pos]==deg[i])a++,b++,pos--;
            pos=i+1;
            while(pos<=n&&deg[pos]==deg[i])b++,pos++;
            ans=(ans+C(b,a))%mod;
        }
    }
    if(S==n*(n-1)/2)ans=(ans-1+mod)%mod;
    cout<<ans<<endl;
    return 0;
}
posted @ 2023-11-13 19:21  Candycar  阅读(15)  评论(0)    收藏  举报