首页 技术 正文
技术 2022年11月15日
0 收藏 977 点赞 3,283 浏览 2062 个字

链接:vjudge

题目大意:有一排方格共 $n$ 个,现在有 $m$ 种颜色,要给这些方格染色,要求相邻两个格子的颜色不能相同。现在问恰好用了 $k$ 种颜色的合法方案数。答案对 $10^9+7$ 取模。$T$ 组数据。

$1\le T\le 300,1\le n,m\le 10^9,1\le k\le 10^6,k\le \min(n,m)$。大多数数据中 $k$ 很小。(smg啊……)


经典的二项式反演例题。

我们令 $f(x)$ 为一共有 $x$ 种颜色,恰好用了 $x$ 种颜色的方案数。

答案就是 ${m\choose k}f(k)$。因为任意选 $k$ 种颜色方案数是一样的。

这……似乎不太好算?

我们再令 $g(x)$ 为一共有 $x$ 种颜色,用了至多 $x$ 种颜色的方案数。

这个就不难算了。第一个格子可以随便填,就是 $x$ 种。后面的格子只要不和上一个颜色相同就行了,就是 $x-1$ 种。

乘法原理一下:$g(x)=x(x-1)^{n-1}$。$x=0$ 时这个式子是 $0$。

但是要注意,$x=n=1$ 时我们这样计算是 $0$,但是实际上是 $1$。为什么?$1\times 0^0$。所以我们要把 $0^0$ 看做 $1$,或者直接特判掉。

(但是不特判也能过,数据太水,这多组数据没用吧)

我们来想一想 $f$ 和 $g$ 有什么关系。很容易发现:$g(x)=\sum\limits^x_{i=0}{x\choose i}f(i)$。因为 $x$ 种颜色中随便选 $i$ 种都可以。

标准二项式反演形式。$f(x)=\sum\limits^x_{i=0}(-1)^{x-i}{x\choose i}g(i)$。

因为 $x\le 10^6$,所以阶乘和逆元都可以预处理,组合数就可以 $O(1)$ 了。此时 $f(x)$ 就可以 $O(x\log n)$ 算了。

现在问题就是算 $m\choose k$ 了。$m$ 达到了惊人的 $10^9$,模数又是个大数……怎么办?

我们发现 $m\choose k$ 可以表示成一种不常用的形式:$\frac{m(m-1)(m-2)…(m-k+1)}{k!}$。

此时分母是预处理过的,分子可以 $O(k)$ 算。这就完事了。

总时间复杂度 $O(Tk\log n)$。因为大多数数据中 $k$ 很小,所以可以跑过。

……这数据范围我给满分……

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=,mod=;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
char ch=getchar();int x=,f=;
while(ch<'' || ch>'') f|=ch=='-',ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return f?-x:x;
}
int t,n,m,k,fac[maxn],inv[maxn],invfac[maxn];
void init(){ //预处理阶乘,逆元,阶乘的逆元
fac[]=fac[]=inv[]=invfac[]=invfac[]=;
FOR(i,,){
fac[i]=1ll*fac[i-]*i%mod;
inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
invfac[i]=1ll*invfac[i-]*inv[i]%mod;
}
}
int C(int n,int m){
if(n<=) return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod; //n,m很小,可以直接算
int ans=invfac[m]; //分母是m的阶乘
ROF(i,n,n-m+) ans=1ll*ans*i%mod; //暴力乘上分子
return ans;
}
int qpow(int a,int b){ //快速幂
int ans=;
for(;b;b>>=,a=1ll*a*a%mod) if(b&) ans=1ll*ans*a%mod;
return ans;
}
int g(int x){
if(x== && n==) return ; //特判掉x=n=1
return 1ll*x*qpow(x-,n-)%mod;
}
int f(int x){
int ans=;
FOR(i,,x){
int v=1ll*C(x,i)*g(i)%mod;
if((x-i)&) ans=(ans-v+mod)%mod; //(-1)^(x-i)
else ans=(ans+v)%mod;
}
return ans;
}
int main(){
init();
t=read();
FOR(tt,,t){
n=read();m=read();k=read();
printf("Case #%d: %d\n",tt,int(1ll*C(m,k)*f(k)%mod)); //记得乘上C(m,k)
}
}

二项式反演

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,946
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,472
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,285
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,101
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,733
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,768