msc的背包(生成函数)

msc的背包
思路:显然分别对大小为1和2的分别构造生成函数
1 + x + x 2 + x 3 + . . . 1+x+x^2+x^3+... 1+x+x2+x3+...= 1 1 − x \frac{1}{1-x} 1x1
1 + x 2 + x 4 + . . . . 1+x^2+x^4+.... 1+x2+x4+.... = 1 1 − x 2 \frac{1}{1-x^2} 1x21
总贡献为 1 ( 1 − x ) n ( 1 − x 2 ) m \frac{1}{(1-x)^n(1-x^2)^m} (1x)n(1x2)m1= 1 ( 1 − x ) n ( 1 − x ) m ( 1 + x ) m \frac{1}{(1-x)^n(1-x)^m(1+x)^m} (1x)n(1x)m(1+x)m1= ( 1 + x ) n ( 1 − x 2 ) n + m \frac{(1+x)^n}{(1-x^2)^{n+m}} (1x2)n+m(1+x)n
分子是二项式定理,分母是广义二项式定理。
由于最后只需要第k项的系数,所以对分子从0遍历到n,那么产生贡献的就是分母的第k-i项系数,其中分母的组合数系数因为分母是固定的,分子每次只整体左移1,所以可以o(1)获得,最终复杂度o(n+m),详细看代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2000000 + 100;
const int INF = 0x7fffffff;
const ll mod =998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
int q_pow(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1)
		{
			res=1ll*res*a%mod;
		}
		b>>=1;
		a=1ll*a*a%mod;
	}
	return res;
}
int F[maxn], Finv[maxn], inv[maxn];
void init(){
    inv[1] = 1;
    for(int i = 2; i < maxn; i ++){
        inv[i] = (mod - mod / i) * 1ll * inv[mod% i] % mod;
    }
    F[0] = Finv[0] = 1;
    for(int i = 1; i < maxn; i ++){
        F[i] = F[i-1] * 1ll * i % mod;
        Finv[i] = Finv[i-1] * 1ll * inv[i] % mod;
    }
}
int comb(int n, int m){
    if(m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	init();
	int y=1;
	for(int i=k/2+1;i<=n+m+k/2-1;i++)
	{
		y=1ll*y*i%mod;
	}
	int l=k/2+1;
	int r=n+m+k/2-1;
	int ans=0;
	for(int i=0;i<=n;i++)
	{
		if((k-i)%2==0)
		{
			if(i>1)
			{
				y=1ll*y*q_pow(r,mod-2)%mod;
				y=1ll*y*(l-1)%mod;
				l--;
				r--;
			}
			ans=(1ll*ans+1ll*comb(n,i)*y%mod*Finv[n+m-1]%mod)%mod;
		}
	}
	cout<<ans<<endl;
  // system("pause");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值