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 = 644222=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=1nCn1i1(i1)!i2dp[ni]

化简得到

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]=(n1)!i=1ni2(ni)!dp[ni]

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]=(n1)!i=1nG[i]F[ni]

观察到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[xl]+...+F[l+(midl)]G[xmid]

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[midl]的位置.

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=ab

最后卷积数组的c[x−l]c[x-l]c[xl]位置的值就是F[x]F[x]F[x].

描述上稍微有点问题,FFFdpdpdp的关系有点混淆,诸位看我代码就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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AT2300-[ARC068C]Snuke Line【整除分块】

正题 题目链接: https://www.luogu.com.cn/problem/AT2300 https://atcoder.jp/contests/arc068/tasks/arc068_c 题目大意 有mmm个车站&#xff0c;nnn种礼品&#xff0c;第iii种可以在[li,ri][l_i,r_i][li​,ri​]的车站买到&#xff0c;第ddd辆车会近过编号为ddd的倍数的车…

【二分】游戏

游戏 题目大意&#xff1a; 有三个套餐&#xff0c;1&#xff1a;一个a、一个b和一个c,2&#xff1a;一个a和两个b&#xff0c;3&#xff1a;两个a和一个b&#xff0c;现在有一定的a、b和c&#xff0c;要使任意两个形同的套餐不相邻&#xff0c;问最多可以有多少个套餐&#…

要用Identity Server 4 -- OAuth 2.0 超级简介

OAuth 2.0 简介OAuth有一些定义:OAuth 2.0是一个委托协议, 它可以让那些控制资源的人允许某个应用以代表他们来访问他们控制的资源, 注意是代表这些人, 而不是假冒或模仿这些人. 这个应用从资源的所有者那里获得到授权(Authorization)和access token, 随后就可以使用这个access…

清明梦超能力者黄YY[树链剖分+扫描线,线段树合并]

清明梦超能力者黄YY 题目连接 https://www.nowcoder.com/acm/contest/206/I 暂时有两种做法. 算法一 涉及:树链剖分,扫描线 在一个线段的情况下,我们可以把一个染色区间拆成左端点处增加事件,右端点处删除事件. 维护一颗权值线段树. 这样,端点从小到大扫描时,遇到增加事件…

初一模拟赛总结(3.23)

成绩&#xff1a; rankrankranknamenamenamescorescorescoreT1T1T1T2T2T2T3T3T3T4T4T4111lyflyflyf300300300100100100100100100100100100000222wjjwjjwjj290290290100100100100100100909090000333hkyhkyhky270270270100100100100100100707070000444fyfyfy24024024010010010010…

CF1110E-Magic Stones【结论题,差分】

正题 题目链接:https://www.luogu.com.cn/problem/CF1110E 题目大意 给出一个序列cic_ici​和一个序列tit_iti​。每次操作可以将cici−1ci1−ci(1<i<n)c_ic_{i-1}c_{i1}-c_i(1<i<n)ci​ci−1​ci1​−ci​(1<i<n) 解题思路 首先要求c1t1,cntnc_1t_1,c_nt…

好代码是管出来的——C#的代码规范

代码是软件开发过程的产物&#xff0c;代码的作用是通过编译器编译后运行&#xff0c;达到预期的效果(功能、稳定性、安全性等等)&#xff0c;而另外一个重要作用是给人阅读。对于机器来说只要代码正确就能够正确的运行程序&#xff0c;但是人不同&#xff0c;如果代码编写混乱…

【图论】【高精】产生数(ssl 1021/ luogu 1037)

产生数 ssl 1021 luogu 1037 题目大意&#xff1a; 有一个数&#xff0c;可以使某些数字变成相对应的数字&#xff0c;问有多少种变法 原题&#xff1a; Description 给出一个整数 n&#xff08;n<10^30) 和 k 个变换规则&#xff08;k<15&#xff09;。   规则…

P3224-[HNOI2012]永无乡【平衡树,启发式合并】

正题 题目链接:https://www.luogu.com.cn/problem/P3224 题目大意 nnn个点&#xff0c;每次可以连接两个点和询问一个点所在联通块中第kkk大的数。 解题思路 我们发现可以启发式合并&#xff0c;对于每个联通块维护一个线段树&#xff0c;然后每次合并时将小的暴力丢入大的平…

牛客国庆集训派对Day6

牛客国庆集训派对Day6 以下是我个人题解,出题人题解附带在最后 A.Birthday 费用流裸题,只要注意到135...2k−1k2135...2k-1 k^2135...2k−1k2即可已做这道题了. 其他的地方连边都很方便.每一个区域向汇点连很多条容量为111的边,但费用分别是1,3,5,...,2k−11,3,5,...,2k-11…

.NET Core微服务之基于IdentityServer建立授权与验证服务(续)

上一篇《.NET Core微服务之基于IdentityServer建立授权与验证服务》我们基于IdentityServer4建立了一个AuthorizationServer&#xff0c;并且继承了QuickStartUI&#xff0c;能够成功获取Token了。这一篇我们了解下如何集成API Service和MVC Web Application。一、集成API Serv…

P4587-[FJOI2016]神秘数【主席树】

正题 题目链接:https://www.luogu.com.cn/problem/P4587 题目大意 nnn个数&#xff0c;每次选择一个区间&#xff0c;然后询问这个区间的子集和所不能表示的最小的正整数。 解题思路 假设我们从小到大加入数字&#xff0c;我们发现如果这个数不是111显然这个区间内至少有一个…

【图论】【Floyed】舞会邀请(CODE[VS] 2604)

舞会邀请 CODE[VS] 2604 题目大意&#xff1a; Smart要叫一些人开Party&#xff0c;每个人可以通知一部分人&#xff0c;Smart去通知一些人&#xff0c;再让这些人去通知其他人&#xff0c;问Smart最少通知几个人&#xff0c;可以使全部人都被通知到 原题&#xff1a; 题目…

ASP.NET Core 2.1 : 十一. 如何在后台运行一个任务

在大部分程序中一般都会需要用到后台任务&#xff0c; 比如定时更新缓存或更新某些状态。一、应用场景以调用微信公众号的Api为例&#xff0c; 经常会用到access_token&#xff0c;官方文档这样描述&#xff1a;“是公众号的全局唯一接口调用凭据&#xff0c;有效期目前为2个小…

【Floyed】工厂的烦恼(ssl 1762)

工厂的烦恼 ssl 1762 题目大意&#xff1a; 求一个图中最长的路线的长度 原题&#xff1a; Description 某工厂发现厂里的机器在生产产品时要消耗大量的原材料&#xff0c;也就是说&#xff0c;有大量的原材料变成了废物。因此厂里想找出消耗原材料最大的一条生产线路进行…

P3899-[湖南集训]谈笑风生【主席树】

正题 题目链接:https://www.luogu.com.cn/problem/P3899 题目大意 给出nnn个点的一棵有根树&#xff0c;每次询问一个(p,k)(p,k)(p,k)&#xff0c;求有多少个点对(b,c)(b,c)(b,c)满足 ppp和bbb是ccc的祖先bbb与ppp的距离不超过kkk 蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤…

好代码是管出来的——.Net中的代码规范工具及使用

上一篇文章好代码是管出来的——C#的代码规范介绍了编码标准中一些常用的工具&#xff0c;本篇就具体来介绍如何使用它们来完成代码管理。  本文主要内容有&#xff1a;Roslyn简介开发基于Roslyn的代码分析器常用的基于Roslyn的代码分析器在.Net Framework项目中使用代码分析…

NCPC2018 D.Delivery Delays[二分答案+DP check]

Delivery Delays 题意 100010001000个点,500050005000条边的无向图,披萨店在111号店.100010001000份披萨订单,每个订单有下单时间,送达地点,披萨制作出来的时间.你是快递员初始在111号点,每次可以拿无穷多披萨,送完以后返回111号点继续送,送餐的时候要求按照下单顺序送达,求等…

P6046-纯粹容器【数学期望,组合数】

正题 题目链接:https://www.luogu.com.cn/problem/P6046 题目大意 nnn个数&#xff0c;每次选择两个相邻的数删除小的那个&#xff0c;求每个数期望存活轮数。 解题思路 相当于一条链每次缩掉一条边&#xff0c;我们发现其实每个点只需要考虑左右第一个比它大的就好了。定义…

【dfs】病毒(jzoj 1284)

病毒 题目大意&#xff1a; 有n&#xff08;1<n<1000&#xff09;头奶牛&#xff0c;d&#xff08;1<d<15&#xff09;种病毒&#xff0c;每头奶牛身上有可能有很多种病毒病毒&#xff0c;每头奶牛挤出的牛奶是混在一起放的&#xff0c;问最多可以挤多少头奶牛的…