题解:P12992 [GCJ 2022 #1C] Intranets
显然
2log 做法
考虑按照边权从大到小插入边,则一条边被激活,当且仅当两个点没有都被标记。随后,我们会标记这两个点。
发现前面的顺序不关心,只关心被标记的点集。
加入一条
那只需求出,
朴素 DP 可以
线性做法
上面除了基础的观察,其余和正解无关。
相当于两个点都没有被标记的次数,就是连通块的个数。相当于加入了
考虑容斥,钦定加入了
因此,我们只需要
考虑
然后考虑如何确定剩余边的排名。容易发现目前这
对于任意的一条未被钦定的边
显然还存在边
由
因此
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=(l);i<=(r);++i)
#define down(i,l,r) for(int i=(l);i>=(r);--i)
#define pi pair<int,int>
#define p1 first
#define p2 second
#define m_p make_pair
#define pb push_back
#define eb emplace_back
#define ppc __builtin_popcountll
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0;short t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*t;
}
const int maxn=1e6+10,p=1e9+7;
int n,k,prd[maxn],g[maxn],fac[maxn],inv[maxn],ifac[maxn],fac2[maxn];
void init(){
int n=1e6;
fac[0]=1;up(i,1,n)fac[i]=fac[i-1]*1llu*i%p;
inv[1]=1;up(i,2,n)inv[i]=(p-inv[p%i])*1llu*(p/i)%p;
ifac[0]=1;up(i,1,n)ifac[i]=ifac[i-1]*1llu*inv[i]%p;
fac2[0]=1;up(i,1,n)fac2[i]=fac2[i-1]*1llu*(2*i-1)%p;
}
inline int C(int n,int m){return fac[m]*1llu*ifac[n]%p*ifac[m-n]%p;}
int T;
void slv(){
n=read(),k=read();
prd[0]=1;up(i,1,n/2)prd[i]=prd[i-1]*1llu*inv[2*n-2*i-1]%p;
up(i,1,n/2)g[i]=prd[i]*1llu*fac2[i]%p*C(2*i,n)%p;
int res=0;
up(i,k,n/2){
int v=g[i]*1llu*C(k,i)%p;
if((i-k)&1)v=p-v;
(res+=v)%=p;
}printf("Case #%d: %d\n",++T,res);
}
int main(){
// freopen("1.in","r",stdin),freopen("1.out","w",stdout);
init();int t=read();while(t--)slv();
return 0;
}