题目描述

  对于一个\(1\)到\(n\)的排列\(a_1,a_2,a_3,\ldots,a_n\),我们定义这个排列的\(P\)值和\(Q\)值:

  对于每个\(a_i\),如果存在一个最小的\(j\)使得\(i<j\)且\(a_i<a_j\),那么将\(a_i\)和\(a_j\)连一条无向边。于是就得到一幅图。计算这幅图每个联通块的大小,将它们相乘,得到\(P\)。记\(Q=P^k\)。

  对于\(1\)到\(n\)的所有排列,我们想知道它们的\(Q\)值之和。由于答案可能很大,请将答案对\(998244353\)取模。

  \(n,k\leq 100000\)

题解

  考虑从小到大插入这\(n\)个数。

  设\(f_i\)为所有\(1\)~\(i\)的排列的\(Q\)值之和。

  考虑\(i\)的位置,当\(i\)在第\(j\)个位置的时候,前面\(j\)个点是联通的,后面\(i-j\)个点与前面\(j\)个点不连通。

\[\begin{align}
f_i&=\sum_{j=1}^i\binom{i-1}{j-1}(j-1)!j^kf_{i-j}\\
f_i&=\sum_{j=1}^i\frac{(i-1)!j^kf_{i-j}}{(i-j)!}\\
f_i&=(i-1)!\sum_{j=1}^ij^k\frac{f_{i-j}}{(i-j)!}
\end{align}
\]

  用分治FFT加速。

  时间复杂度:\(O(n\log k+n\log^2n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
while(b)
{
if(b&1)
s=s*a%p;
a=a*a%p;
b>>=1;
}
return s;
}
namespace ntt
{
const ll g=3;
ll w1[270010];
ll w2[270010];
int rev[270010];
int n;
void init(int m)
{
n=1;
while(n<m)
n<<=1;
int i;
for(i=2;i<=n;i<<=1)
{
w1[i]=fp(g,(p-1)/i);
w2[i]=fp(w1[i],p-2);
}
rev[0]=0;
for(i=1;i<n;i++)
rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
}
void ntt(ll *a,int t)
{
ll u,v,w,wn;
int i,j,k;
for(i=0;i<n;i++)
if(rev[i]<i)
swap(a[i],a[rev[i]]);
for(i=2;i<=n;i<<=1)
{
wn=(t==1?w1[i]:w2[i]);
for(j=0;j<n;j+=i)
{
w=1;
for(k=j;k<j+i/2;k++)
{
u=a[k];
v=a[k+i/2]*w%p;
a[k]=(u+v)%p;
a[k+i/2]=(u-v)%p;
w=w*wn%p;
}
}
}
if(t==-1)
{
ll inv=fp(n,p-2);
for(i=0;i<n;i++)
a[i]=a[i]*inv%p;
}
}
ll x[270010];
ll y[270010];
void copy_clear(ll *a,ll *b,int m)
{
int i;
for(i=0;i<m;i++)
a[i]=b[i];
for(i=m;i<n;i++)
a[i]=0;
}
void copy(ll *a,ll *b,int m)
{
int i;
for(i=0;i<m;i++)
a[i]=b[i];
}
void inverse(ll *a,ll *b,int m)
{
if(m==1)
{
b[0]=fp(a[0],p-2);
return;
}
inverse(a,b,m>>1);
init(2*m);
copy_clear(x,a,m);
copy_clear(y,b,m>>1);
ntt(x,1);
ntt(y,1);
int i;
for(i=0;i<n;i++)
x[i]=(2*y[i]%p-x[i]*y[i]%p*y[i]%p+p)%p;
ntt(x,-1);
copy(b,x,m);
}
};
ll fac[300010];
ll ifac[300010];
ll inv[300010];
ll f[300010];
ll a[300010];
ll b[300010];
ll ex[300010];
int n,k;
void solve(int l,int r)
{
if(l==r)
{
f[l]=f[l]*fac[l-1]%p;
return;
}
int mid=(l+r)>>1;
solve(l,mid);
ntt::init(r-l+1);
int i;
for(i=l;i<=mid;i++)
a[i-l]=f[i]*ifac[i];
for(i=l;i<=r;i++)
b[i-l]=ex[i-l];
for(i=mid-l+1;i<ntt::n;i++)
a[i]=0;
for(i=r-l+1;i<ntt::n;i++)
b[i]=0;
ntt::ntt(a,1);
ntt::ntt(b,1);
for(i=0;i<ntt::n;i++)
a[i]=a[i]*b[i]%p;
ntt::ntt(a,-1);
for(i=mid+1;i<=r;i++)
f[i]+=a[i-l];
solve(mid+1,r);
}
int main()
{
open("xsy2166");
scanf("%d%d",&n,&k);
int i;
fac[0]=fac[1]=ifac[0]=ifac[1]=inv[0]=inv[1]=1;
for(i=2;i<=n;i++)
{
inv[i]=-(p/i)*inv[p%i]%p;
fac[i]=fac[i-1]*i%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
for(i=1;i<=n;i++)
{
ex[i]=fp(i,k);
f[i]=ex[i];
}
solve(1,n);
ll ans=(f[n]+p)%p;
printf("%lld\n",ans);
return 0;
}

【XSY2166】Hope 分治 FFT的更多相关文章

  1. BNUOJ 51279[组队活动 Large](cdq分治+FFT)

    传送门 大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案.两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中 ...

  2. hdu 5730 Shell Necklace [分治fft | 多项式求逆]

    hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...

  3. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  4. 分治FFT的三种含义

    分治FFT是几个算法的统称.它们之间并无关联. 分治多项式乘法 问题如求\(\prod_{i=1}^na_ix+b\). 若挨个乘复杂度为\(O(n^2\log n)\),可分治做这件事,复杂度为\( ...

  5. 【XSY2666】排列问题 DP 容斥原理 分治FFT

    题目大意 有\(n\)种颜色的球,第\(i\)种有\(a_i\)个.设\(m=\sum a_i\).你要把这\(m\)个小球排成一排.有\(q\)个询问,每次给你一个\(x\),问你有多少种方案使得相 ...

  6. 【XSY2887】【GDOI2018】小学生图论题 分治FFT 多项式exp

    题目描述 在一个 \(n\) 个点的有向图中,编号从 \(1\) 到 \(n\),任意两个点之间都有且仅有一条有向边.现在已知一些单向的简单路径(路径上任意两点各不相同),例如 \(2\to 4\to ...

  7. prime distance on a tree(点分治+fft)

    最裸的点分治+fft,调了好久,太菜了.... #include<iostream> #include<cstring> #include<cstdio> #inc ...

  8. 【XSY2744】信仰圣光 分治FFT 多项式exp 容斥原理

    题目描述 有一个\(n\)个元素的置换,你要选择\(k\)个元素,问有多少种方案满足:对于每个轮换,你都选择了其中的一个元素. 对\(998244353\)取模. \(k\leq n\leq 1525 ...

  9. 【BZOJ5119】【CTT2017】生成树计数 DP 分治FFT 斯特林数

    CTT=清华集训 题目大意 有\(n\)个点,点权为\(a_i\),你要连接一条边,使该图变成一颗树. 对于一种连边方案\(T\),设第\(i\)个点的度数为\(d_i\),那么这棵树的价值为: \[ ...

随机推荐

  1. nodejs图片处理工具gm用法

    在做H5应用中,有时候会涉及到一些图片加工处理的操作,nodejs有一个很好的后台图片处理module,就是这里说的gm.gm有官方文档,但感觉写得太抽象,反而看不懂了.这里把一些常见的用法写下,供大 ...

  2. oc之考试答题类效果

    https://www.jianshu.com/p/ec29feb0b5a6 2017.07.27 11:48* 字数 424 阅读 615评论 9喜欢 11 demo地址:https://githu ...

  3. Linux系统tree工具

    当用户在linux平台中需要需要查看一个非当前目录的目录下有哪些文件和子文件时,最普通的办法就是cd该目录,然后再ls,这个操作令人不舒适,因为查看完以后,用户还需要切换到原来的目录.现在介绍一款非常 ...

  4. Swagger UI 用法

    Swagger - 简书https://www.jianshu.com/p/4115f2b53983 Swagger简介 - Ghost Stories - CSDN博客https://blog.cs ...

  5. vs快捷键 C#

    快速构建构造函数 输入 ctor 然后按 TAB 键 快速构建自动属性 在变量那里,右击鼠标,点“重构”--“封装字段” Visual Studio快捷键 [VS2008/VS2005] ****** ...

  6. Git - 常见错误与解决方案

    1.windows使用git时出现:warning: LF will be replaced by CRLF 分析: windows中的换行符为 CRLF, 而在linux下的换行符为LF,所以在执行 ...

  7. C#设计模式之1:策略模式

    首先需要说明的是该系列的所有内容都是基于headfirst设计模式来描述的.因为我之前也看过不少关于设计模式的书,还是发现这本最好,因为这本书里面给出的例子是最贴切实际的.不说了,开始这个系列吧! 策 ...

  8. 机顶盒webview开发调试

    安装node的anywhere插件  启动本地服务器后 使用chrome的DevTool----->   chrome://inspect/#devices 点击inspect  第一次需要FQ ...

  9. prop与attr

    1.都是获取当前元素某个属性的值 2.当获取多选框的状态时,如果没有选中,此时没有checked属性,用attr获取得到undifien prop得到false. 3.html原生属性用prop获取, ...

  10. DAY01、计算机组成及操作系统

    一.编程与编程的目的: 1.什么是语言?什么是编程语言? 语言是一事物与另一事物之间沟通的介质 编程语言就是程序员与计算机之间沟通的介质 2.什么是编程? 程序员把自己想要让计算机做的事用编程语言表达 ...