HDU5322 - cdq分治FFT加速dp
5322 Hope [CDQ分治FFT加速计算dp]
题意
每一个每一个排列,排列中每个数向它后面第一个比它大的数连一条边.
每个排列对于答案的贡献是这个排列所生成的图中的每一个联通量中点的个数的平方之积.
例如:排列
1,2,3,6,4,51,2,3,6,4,51,2,3,6,4,5
其中
1,2,3,61,2,3,61,2,3,6形成一个大小为444的联通分量.
4,54,54,5形成一个大小为222的联通分量.
那么这个排列的贡献就是42∗22=644^2*2^2 = 6442∗22=64.
我们需要求所有排列的贡献.
题解
这种题做法一般就是dpdpdp.
我们枚举排列中最大的数nnn的所在的位置,当nnn的位置固定以后,所有在nnn前面的数都会与nnn形成一个连通分量.而后面的所有的数就组成了一个子问题.
定义dp[n]dp[n]dp[n]表示nnn的所有排列所形成的贡献之和.
我们可以得到递推公式.
dp[n]=∑i=1nCn−1i−1∗(i−1)!∗i2∗dp[n−i]dp[n] = \sum_{i=1}^{n}C_{n-1}^{i-1}*(i-1)!*i^2*dp[n-i]dp[n]=∑i=1nCn−1i−1∗(i−1)!∗i2∗dp[n−i]
化简得到
dp[n]=(n−1)!∑i=1ni2∗dp[n−i](n−i)!dp[n] = (n-1)!\sum_{i=1}^{n}i^2*\frac{dp[n-i]}{(n-i)!}dp[n]=(n−1)!∑i=1ni2∗(n−i)!dp[n−i]
记F[i]=dp[i]i!,G[i]=i2F[i]=\frac{dp[i]}{i!},G[i]=i^2F[i]=i!dp[i],G[i]=i2
那么
dp[n]=(n−1)!∑i=1nG[i]F[n−i]dp[n] = (n-1)!\sum_{i=1}^{n}G[i]F[n-i]dp[n]=(n−1)!∑i=1nG[i]F[n−i]
观察到dp[n]dp[n]dp[n]的递推公式是一个卷积的形式.
求卷积我们显然想到了FFT/NTTFFT/NTTFFT/NTT来加速dpdpdp的计算,对于要求出所有的dp[n]dp[n]dp[n],因此我们需要用CDQCDQCDQ分治来辅助计算FFT/NTTFFT/NTTFFT/NTT.
采用分治策略,即将区间F[l,r]F[l,r]F[l,r]分成区间F[l,mid]F[l,mid]F[l,mid]和F[mid+1,r]F[mid+1,r]F[mid+1,r]两个区间.
用F[l,mid]F[l,mid]F[l,mid]区间的内容和GGG多项式做卷积,即可计算出F[l,mid]F[l,mid]F[l,mid]部分对于F[mid+1,r]F[mid+1,r]F[mid+1,r]的影响.注意!这里要求F[l,mid]F[l,mid]F[l,mid]必须已经完整的被计算出来了.随后再地归计算F[mid+1,r]F[mid+1,r]F[mid+1,r]部分,解决它们内部的贡献以来.
因此代码的大致框架就是:
void solve(int l,int r) {if(l == r) return ;int mid = (l + r) >> 1;solve(l,mid);//保证区间F[l,mid]已经被完整的计算出来了Conv();//求卷积,计算F[l,mid]对F[mid+1,r]的贡献.注意此时F[1,l-1]对F[mid+1,r]的贡献早已被求过了.//注意在此时,F[mid+1,r]内部依赖于F[1,mid]的贡献已经全部被计算出来了,因此下一步求内部F[mid+1,r]对F[mid+1,r]的贡献.solve(mid+1,r);
}
举个栗子
当n=4n=4n=4时刻
初始[1,1][1,1][1,1]就算完整的被计算出来了.
先求[1,1][1,1][1,1]对[2,2][2,2][2,2]的贡献,从而得到了完整的[1,2][1,2][1,2].
然后计算[1,2][1,2][1,2]对[3,4][3,4][3,4]的贡献,此时[3,3][3,3][3,3]已经被完整的计算出来了.
然后算[3,3][3,3][3,3]对于[4,4][4,4][4,4]的贡献,导致[4,4][4,4][4,4]被完整的计算出来.
至此[1,4][1,4][1,4]都被完整的计算出来了.
注意
其中计算[l,mid][l,mid][l,mid]对[mid+1,r][mid+1,r][mid+1,r]的贡献的时候,需要注意:
x∈[mid+1,r]x \in [mid+1,r]x∈[mid+1,r]
F[x]←F[l+0]∗G[x−l]+...+F[l+(mid−l)]∗G[x−mid]F[x] \leftarrow F[l+0]*G[x-l] + ... + F[l+(mid-l)]*G[x-mid]F[x]←F[l+0]∗G[x−l]+...+F[l+(mid−l)]∗G[x−mid]
将F[l],F[l+1],...,F[mid]F[l],F[l+1],...,F[mid]F[l],F[l+1],...,F[mid]填在数组a[0],a[1],...,a[mid−l]a[0],a[1],...,a[mid-l]a[0],a[1],...,a[mid−l]的位置.
将G[0],G[1],G[2],...,G[n]G[0],G[1],G[2],...,G[n]G[0],G[1],G[2],...,G[n]填在数组b[0],b[1],b[2],..,b[n]b[0],b[1],b[2],..,b[n]b[0],b[1],b[2],..,b[n]的位置.
然后求个卷积c=a⨂bc = a\bigotimes bc=a⨂b
最后卷积数组的c[x−l]c[x-l]c[x−l]位置的值就是F[x]F[x]F[x].
描述上稍微有点问题,FFF和dpdpdp的关系有点混淆,诸位看我代码就ok了.
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
#define clr(x) memset(x,0,sizeof(x))
#define setinf(x) memset(x,0x3f,sizeof(x))
#define Max(x,y) x = std::max(x,y)
#define Min(x,y) x = std::min(x,y)
#define Add(x,y) x = (((x)+(y))%P)
#define Sub(x,y) x = (((x)-(y)+P%P)
#define Mul(x,y) x = ((x)*(y)%P)
typedef long long LL;
const int N = 1 << 20;
const int P = 998244353;
const int G = 3;
const int NUM = 20;LL wn[NUM];
LL a[N], b[N];LL quick_mod(LL a, LL b, LL m)
{LL ans = 1;a %= m;while(b){if(b & 1){ans = ans * a % m;b--;}b >>= 1;a = a * a % m;}return ans;
}void GetWn()
{for(int i = 0; i < NUM; i++){int t = 1 << i;wn[i] = quick_mod(G, (P - 1) / t, P);}
}
void Rader(LL a[], int len)
{int j = len >> 1;for(int i = 1; i < len - 1; i++){if(i < j) std::swap(a[i], a[j]);int k = len >> 1;while(j >= k){j -= k;k >>= 1;}if(j < k) j += k;}
}void NTT(LL a[], int len, int on)
{Rader(a, len);int id = 0;for(int h = 2; h <= len; h <<= 1){id++;for(int j = 0; j < len; j += h){LL w = 1;for(int k = j; k < j + h / 2; k++){LL u = a[k] % P;LL t = w * a[k + h / 2] % P;a[k] = (u + t) % P;a[k + h / 2] = (u - t + P) % P;w = w * wn[id] % P;}}}if(on == -1){for(int i = 1; i < len / 2; i++)std::swap(a[i], a[len - i]);LL inv = quick_mod(len, P - 2, P);for(int i = 0; i < len; i++)a[i] = a[i] * inv % P;}
}void Conv(LL a[], LL b[], int n)
{NTT(a, n, 1);NTT(b, n, 1);for(int i = 0; i < n; i++)a[i] = a[i] * b[i] % P;NTT(a, n, -1);
}LL dp[N],Fac[N],iFac[N];void solve(int l,int r) {if(l == r) return ;int mid = (l + r) >> 1;solve(l,mid);int len = 1;while(len <= (r-l+1)) len <<= 1;rep(i,0,len) {b[i] = 1LL*i*i%P;}rep(i,l,mid) {a[i-l] = dp[i]*iFac[i]%P;}rep(i,mid-l+1,len) a[i] = 0;Conv(a,b,len);rep(i,mid+1,r) {dp[i] = (dp[i] + (a[i-l]*Fac[i-1]%P))%P;}solve(mid+1,r);
}int main()
{Fac[0] = iFac[0] = 1;rep(i,1,N-1) {Fac[i] = Fac[i-1]*i % P;iFac[i] = quick_mod(Fac[i],P-2,P);}GetWn();dp[0] = 1;solve(0,100000);int n;while(std::cin >> n) {std::cout << dp[n] << std::endl;}return 0;
}
HDU5322 - cdq分治FFT加速dp相关推荐
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...
- NOI2007 货币兑换 - CDQ分治斜率优化dp
斜率优化dp维护一个凸壳.如果\(x, y\)坐标都递增,可以用单调队列,如果只有\(x\)递增,可以在凸壳上二分斜率,如果\(x, y\)都不递增,则需要在凸包中插入,可以用平衡树或cdq分治维护. ...
- 【CDQ分治+FFT】LGP4566 [CTSC2018]青蕈领主
[题目] 原题地址 有一个长度为 n n n的排列 a a a,给定 l i l_i li,表示 a i − l i + 1 - a i a_{i-l_i+1} \dots a_i ai−li+1 ...
- CF932F-Escape Through Leaf【树上启发式合并,CDQ分治,斜率优化dp】
正题 题面链接:https://www.luogu.com.cn/problem/CF932F 题目大意 nnn个点的一棵树,从xxx跳到yyy(要求yyy在xxx的子树中)会产生Ax∗ByA_x*B ...
- HDU5730 FFT+CDQ分治
题意:dp[n] = ∑ ( dp[n-i]*a[i] )+a[n], ( 1 <= i < n) cdq分治. 计算出dp[l ~ mid]后,dp[l ~ mid]与a[1 ~ r-l ...
- Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)
题目 Source http://www.tsinsen.com/A1493 Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在 ...
- BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)
BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...
- 【牛客 - 157F】三轮(dp,分治fft)
题干: 链接:https://ac.nowcoder.com/acm/contest/157/F 来源:牛客网 小k有一个三轮,它最多可以装105大小的东西 小k有n种商品,他要准备出摊了 每种商品体 ...
- 【bzoj 1492】【codevs 1797】 [NOI2007]货币兑换Cash (dp+cdq分治)
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MB Submit: 3803 Solved: 1604 [Submit][S ...
最新文章
- bootstrap之 formgroup表单布局样式
- Linux命令速查表
- canvas 绘制跟随鼠标移动的线条
- 22张图片倒叙霍金:我爱宇宙也爱这苦乐人生
- java中审核订单流程图_「数据架构」数据流程图:实例-订餐系统
- 九章算术卷第一 方田
- 像个字段相减绝对值_张歆艺做家务受伤,袁弘俩字逗乐媳妇,真是幼稚得像个大龄儿童...
- 学习笔记整理之小实现
- php将简单的数据从数据库,php将session保存到数据库的简单示例
- Super超图,GIS软件
- C语言函数调用常见问题(1)
- 哪些思维让你受益匪浅
- Keil编译*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
- 银联支付(网银h5)
- java.lang.UnsatisfiedLinkError: Couldn't load XXX
- 现在开房都不需要在前台办理入住了?刺激
- 曹二众 / jeewms仓储管理系统本地部署踩坑记录
- 卸载php和apache,怎么卸载apache服务器
- 使用log4j的邮件功能
- Xcode 7各版本(dmg)官方直接下载(离线下载)
热门文章
- 计算机语言学考研科目,语言学考研笔记整理(共16页)
- 三相全桥整流电路_三相桥式全控整流电路
- 46. 全排列015(回溯法求解)
- 7-8 数字三角形 (31 分)(思路+详解+动态规划)Come Baby!!!!!!!!!!!
- [JavaWeb-HTML]HTML标签_表格标签
- ltv价值 应用_用户终生价值Ltv是什么,在游戏设计中如何考虑?
- python3 beautifulsoup 表格,使用Python中的BeautifulSoup拉取特定的表数据
- java写dnf外掛_dnf卡盟_Java的泛型详解(一)
- windows 编译 caffe unresolved externals 问题
- 命令行操作mysql