题目链接: 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)】
推荐阅读
- 牛客算法周周练15——A、B
- Codeforces Round #609 (Div. 2)——C. Long Beautiful Integer(思维)
- FZU - 2107题解
- ACM OJ 2036 多边形面积计算
- #|【牛客】牛客练习赛67-E-牛妹游历城市——位运算优化
- ACM|回文树(自动机)(练习和总结)
- acm|扩展欧几里德算法(附证明)
- ACM|[dsu] codeforces 375D. Tree and Queries
- ACM|codeforces 732-D. Exams (二分)