ACM|HDU 5322 Hope (CDQ分治+NTT)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5322

题意: 给定n,考虑一个1,2,...,n的排列A[1],A[2],...,A[n],对于每个i,选取最小的j(若存在)使得j>i且A[j]>A[i],则在i到j之间连一条边,记P为图中所有连通块的大小之积,定义P*P为这个排列的permutation value,求出所有1,2,...,n的排列的permutation value之和对998244353取模的值。

分析:
记dp[i]为所有1,2,...,i的排列的permutation value之和,
考虑i的位置,当i位于第j个位置时,前j个点是连通的,且后i-j个点与前j个点不连通,
这里对答案的贡献为C(i-1,j-1)*(j-1)!*j^2*dp[i-j],
不妨设dp[0]=1,
则dp[i]=sigma_(j=1~i)(C(i-1,j-1)*(j-1)!*j^2*dp[i-j]),
可以将上式整理成卷积形式,
由于要求出所有的dp值,考虑用CDQ分治进行优化,
假设现在要处理[l,r]的结果,
先递归处理[l,m]的结果,
然后用FFT计算[l,m]的结果对[m+1.r]的贡献,
再递归处理[m+1,r]的结果,
由于模数998244353=119*2^23+1,
可以使用NTT来保证计算过程中的精度,
那么有T[n]=2*T[n/2]+O(nlogn),
总复杂度T[n]=O(n*(logn)^2)。


代码:

#include #include #include #include #include #include using namespace std; typedef long long ll; const ll Mod=998244353; const ll g=3; ll fp(ll a,ll k) { ll res=1LL; while(k>0) { if(k&1)res=res*a%Mod; a=a*a%Mod; k>>=1; } return res; } ll f[100005],inv[100005]; void change(ll y[],int len) { for(int i=1,j=len/2; i=k) { j-=k; k/=2; } if(j>1; cdq(l,m); int len=1; while(len<=r-l+1)len<<=1; for(int i=0; i

【ACM|HDU 5322 Hope (CDQ分治+NTT)】

    推荐阅读