二项式反演,莫比乌斯反演。

xiaoxiao2021-02-28  31

1、设出两个函数,f(i),g(i)。

要求其满足条件f(n)=sigm(i=0到i=n)C(n,i)g(i)

然后根据这个条件,可以推导出

g(n)=sigm(i=0到i=n)C(n,i)*(-1)^(n-i)f(i)

意思是得出了一个函数可以求出另外一个函数

莫比乌斯反演,O(N)求法

const int N = 1e6 + 5; int mu[N], vis[N], prime[N]; int tot;//用来记录prime的个数 void init(){ mu[1] = 1; for(int i = 2; i < N; i ++){ if(!vis[i]){ prime[tot ++] = i; mu[i] = -1; } for(int j = 0; j < tot && i * prime[j] < N; j ++){ vis[i * prime[j]] = 1; if(i % prime[j]) mu[i * prime[j]] = -mu[i]; else{ mu[i * prime[j]] = 0; break; } } } }

例子:

HDU1465

 设g(i)表示正好有i封信装错信封

那么sigmC(n,i)*g(i) 就为将n个信封装入的所有可能数量。

令其为f(n)=n!; 因为正好这么令f(i)是满足条件的

那么g(n)=sigm(i=0到i=n)C(n,i)*(-1)^(n-i)f(i)

那么求出g(n)即可

#include <iostream> #include <iomanip> #include <stdio.h> #include <string.h> #include <stack> #include <map> #include <vector> #include <algorithm> #include <set> #include <queue> #include <math.h> using namespace std; const int MOD=1e9+7; long long f[50]; int init(){ memset(f,0,sizeof(f)); f[0]=1; for(int i=1;i<=20;i++){ f[i]=i*f[i-1]; } } int main(){ freopen("in.txt","r",stdin); // freopen("out1.txt","w",stdout); int t1,t2,t3,t4,n,m,i,j,k,f1,f2,f3,f4; int l,r,c,x,y,num; int T; init(); long long g1,g2,g3; int ans; while(scanf("%d",&n)==1){ ans=pow(-1,n); g1=0; for(i=0;i<=n;i++){ g1+=ans*f[n]/f[n-i]; ans=-ans; } cout << g1<< endl; } return 0; }

UVALive 7040

题意:给n盆花涂色,从m种颜色中选取k种颜色涂,保证正好用上k种颜色,你必须用上这k种颜色去涂满n个相邻的花,并且要求相邻花的颜色不同,求方案数。

 (1 ≤ n, m ≤ 1e9 , 1 ≤ k ≤ 1e6 , k ≤ n, m)

首先找出满足二项式反演的f(i)与g(i)

令g(i)为准确用i种颜色把花盆全部涂满的方法。

令f(i)为用i种颜色把花盆全部涂满的方法。

那么对于k种颜色,涂花的方法数有k*(n-1)^(k-1)

此时f(n)=sigm(i=2到i=n)C(n,i)g(i)=k*(n-1)^(k-1)

那么g(n)=sigm(i=2到i=n)C(n,i)*f(i)*(-1)^(n-i)

此时要求的就是C(m,k)g(k)

转载请注明原文地址: https://www.6miu.com/read-1000346.html

最新回复(0)