BNUOJ 51279[组队活动 Large](cdq分治+FFT)
2016-02-29 00:15
302 查看
传送门
大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案。两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中有不同的队友。
这年头真是……分治FFT都开始烂大街了……
我们来推一推吧
这显然是一个1d1d的DP,用f[i]表示i名队员的方案数
f[i]=∑j=0i−1f[i−j−1]∗Cji−1
即i−1个人里面选j个和i组队(似乎类似strling数)
然后化一下简,便可得到
f[i]=(i−1)!∑j=0i−1f[i−j−1](i−j−1)!∗1j!
一看这不是一个裸的卷积吗?是不是很一颗赛艇!我们就可以用NTT来优化一下了
考虑cdq分治处理[L,R],我们先递归处理[L,Mid],然后把[L,Mid]的f值取出来和(j!)−1来卷一卷。我们就可以得到[L,Mid]对[Mid+1,R]的贡献了。是不是很愉♂快啊!
我不知道其他人怎么写的,比我的慢这么多……
大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案。两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中有不同的队友。
这年头真是……分治FFT都开始烂大街了……
我们来推一推吧
这显然是一个1d1d的DP,用f[i]表示i名队员的方案数
f[i]=∑j=0i−1f[i−j−1]∗Cji−1
即i−1个人里面选j个和i组队(似乎类似strling数)
然后化一下简,便可得到
f[i]=(i−1)!∑j=0i−1f[i−j−1](i−j−1)!∗1j!
一看这不是一个裸的卷积吗?是不是很一颗赛艇!我们就可以用NTT来优化一下了
考虑cdq分治处理[L,R],我们先递归处理[L,Mid],然后把[L,Mid]的f值取出来和(j!)−1来卷一卷。我们就可以得到[L,Mid]对[Mid+1,R]的贡献了。是不是很愉♂快啊!
我不知道其他人怎么写的,比我的慢这么多……
#include <cstdio> #include <algorithm> #include <cstring> #define MAXN 300005 #define LL long long const LL MOD = 998244353LL, g = 3, T = 262144; int n, k; LL w[MAXN], inv[MAXN], invf[MAXN], dp[MAXN], x1[MAXN], x2[MAXN], jc[MAXN], tmp; inline void Swap(LL &a, LL &b) { tmp=a; a=b; b=tmp; } LL ksm(LL a, LL k) { LL ans = 1; for(; k; k >>= 1) { if(k&1) ans = ans * a % MOD; a = a * a % MOD; } return ans; } inline void Init() { LL r = ksm(g, (MOD-1)/T); w[0] = 1; invf[0] = inv[0] = invf[1] = inv[1] = jc[1] = 1; for(int i = 1; i < T; ++ i) w[i] = w[i-1] * r % MOD; for(int i = 2; i < T; ++ i) jc[i] = jc[i-1] * i % MOD; for(int i = 2; i < T; ++ i) inv[i] = (MOD-MOD/i) * inv[MOD%i] % MOD; for(int i = 2; i < T; ++ i) invf[i] = (invf[i-1]*inv[i]) % MOD; } inline void NTT(LL *a, int n, int f) { int i, j, k; for(i = 0, j = 0; i < n; ++ i) { if(i > j) Swap(a[i], a[j]); for(k = (n>>1); (j^=k) < k; k >>= 1); } for(i = 1; i < n; i <<= 1) for(j = 0; j < n; j += i<<1) for(k = 0; k < i; ++ k) { LL x = a[j + k], y = w[T/(i<<1)*k] * a[j + k + i] % MOD; a[j + k] = (x + y) % MOD; a[j + k + i] = (x + MOD - y) % MOD; } LL invn; if(-1 == f) for(std::reverse(a+1, a+n), invn = ksm(n, MOD-2), i = 0; i < n; ++ i) a[i]= a[i] * invn % MOD; } void cdq(int L, int R) { if(L == R) return; int mid = (L + R) >> 1; cdq(L, mid); int len = 1; for(; len <= (R-L+1); len <<= 1); for(int i = 0; i < len; ++ i) { x1[i] = (i < k) ? invf[i] : 0; x2[i] = (L + i <= mid) ? dp[L + i] : 0; } NTT(x1, len, 1); NTT(x2, len, 1); for(int i = 0; i < len; ++ i) x1[i] = (x1[i] * x2[i]) % MOD; NTT(x1, len, -1); for(int i = mid+1; i <= R; ++ i) dp[i] = (dp[i] + x1[i-L-1]*inv[i]) % MOD; cdq(mid+1, R); } int main() { Init(); int T; scanf("%d", &T); while(T --) { scanf("%d%d", &n, &k); memset(dp, 0, sizeof dp); dp[0] = 1; cdq(0, n); printf("%lld\n", dp *jc %MOD); } }
相关文章推荐
- java 命令对象简单学习实现:
- BNUOJ 51279[组队活动 Large](cdq分治+FFT)
- Android性能优化-泛谈 (一)
- Android异步下载图片并且缓存图片到本地
- Android抽象布局——include、merge 、ViewStub
- Cocos2dx工程总结
- 安卓开发环境搭建
- Android 微信支付
- 手表开发中的CrashHandler
- iOS MVC设计模式与MVVM设计模式简介 —— HERO博客
- 我的butterKnife注解开发框架
- 手表开发中的ConcurrentHashMap
- PL/SQL之存储过程处理
- EasyUI文档学习心得
- pypi 的使用
- 我的recycleview示例
- mybatis模糊查询
- [iOS] 绘图 CGContext 用法
- nginx安装第三方模块的方法
- mybatis连接mysql数据库插入中文乱码