题目链接

以下把值域(题面里的\(lim\))记做\(m\)。

考虑求\(k\)的答案。考虑每个位置对答案的贡献,枚举位置\(i\),再枚举\(a[i]\)的值\(x\)。设:
\[
F(k)=\sum_{i=k+1}^{n}m^{i-k-1}m^{n-i}{i-1\choose k}\sum_{x=1}^{m}(x-1)^k
\]
如果对着式子打一个\(O(n^2m)\)的暴力,就会发现这个\(F(k)\)并不是答案,它比答案大。它其实是\(i\)前面至少有\(k\)个数的方案数。而一个序列,如果\(i\)前面有超过\(k\)个\(\leq x\)的数,比方说有\(j\)个,那这个序列就会被计算\(j\choose k\)次。形式化地说,如果设\(i\)前面恰好有\(k\)个\(\leq x\)数的方案数为\(G(k)\),则:
\[
F(k)=\sum_{i=k}^{n}{i\choose k}G(i)
\]
而这个\(G(k)\)的后缀和,就是我们要求的答案。

根据二项式反演,可知:
\[
G(k)=\sum_{i=k}^{n}(-1)^{i-k}{i\choose k}F(i)
\]
如果知道了\(F[1\dots n]\),就可以用NTT快速求出\(G[1\dots n]\),进而求出答案。这部分我们稍后再说,先看如何求\(F\)。

设\(S(m,k)=\sum_{i=0}^{m-1}i^k\)。则:
\[
\begin{align}
F(k)=&m^{n-k-1}S(m,k)\sum_{i=k+1}^{n}{i-1\choose k}\\
=&m^{n-k-1}S(m,k)\sum_{i=k}^{n-1}{i\choose k}\\
=&m^{n-k-1}S(m,k){n\choose k+1}
\end{align}
\]
最后一步相当于求杨辉三角上连续若干行,每行的第\(k\)个数的和(画出来是一条斜向左下的斜线)。可以从上到下把每两个数合并为下一行的第\(k+1\)个数。因此\(\sum_{i=k}^{n-1}{i\choose k}={n\choose k+1}\)。

现在的难点是求出对所有\(k\in[1,n]\),求出\(S(m,k)\)。构造\(S(m,k)\)的指数生成函数\(H(x)=\sum_{i=0}^{\infty}S(m,i)\frac{x^i}{i!}\),则:
\[
\begin{align}
H(x)&=\sum_{i=0}^{\infty}\frac{x^i}{i!}\sum_{j=0}^{m-1}j^i\\
&=\sum_{j=0}^{m-1}\sum_{i=0}^{\infty}\frac{x^ij^i}{i!}
\end{align}
\]
根据小学二年级学过的泰勒展开,我们知道,\(e^x=\sum_{i=0}^{\infty}\frac{x^i}{i!}\)。把这里的\(x\)替换为\((jx)\),则:
\[
\begin{align}
H(x)&=\sum_{j=0}^{m-1}e^{jx}\\
&=\frac{e^{mx}-1}{e^x-1}
\end{align}
\]
注:这一步变换是等比数列求和,即把式子整体乘以\(e^x\)再用新式子减去原式。

再次感谢泰勒展开,我们知道分子和分母其实分别是两个无限长的数列。我们要求是\(H(x)\)的前\(n\)项的值。这个值显然只和两个数列的前\(n\)项有关,因此取出分母的前\(n\)项,做多项式求逆,再用NTT把两个数列乘起来即可。分母的常数项是\(0\)不好处理,但注意到分子的常数项也是\(0\),我们只要把分子分母同时除以\(x\)就行,即两个数列分别左移一位就行。

这样,我们就求出了\(F[0\dots n-1]\),回顾开头部分的讨论,我们要求出:\(G(k)=\sum_{i=k}^{n-1}(-1)^{i-k}{i\choose k}F(i)\quad k\in[0,n-1]\)。

把组合数拆开,得到:
\[
G(k)=\sum_{i=k}^{n-1}(-1)^{i-k}\frac{i!}{k!(i-k)!}F(i)
\]
先把\(k!\)拎出来。然后设\(f_i=i!F(i),g_i=(-1)^i\frac{1}{i!}\),则:
\[
G(k)=k!\sum_{i=k}^{n-1}f_ig_{i-k}
\]
我们熟悉的卷积都是\(c_k=\sum_{i=0}^{k}a_ib_{k-i}\),而这里的形式是\(c_k=\sum_{i=k}^{n}f_ig_{i-k}\),考虑如何转化。注:这里为方便表述,我们令\(n=n-1\)。

仔细考虑卷积的本质,我们的目标是要让相乘的两个数下标之和为定值,而我们能做的事就是尝试翻转一个数列。不妨尝试翻转\(f\),即令\(f_i=f_{n-i}\)。

此时\(c_k=\sum_{i=k}^{n}f_{n-i}g_{i-k}\)。

把\(i\)换成\(i-k\),则\(c_k=\sum_{i=0}^{n-k}f_{n-k-i}g_{i}\)。发现\(f\)和\(g\)的下标和为\(n-k\),刚好是一个定值。此时如果把\(f\)和\(g\)卷起来,那么结果的第\(n-k\)项就是\(c_k\)。再乘上\(k!\)就是\(G(k)\)了。

求出\(G\)后,做后缀和,得到答案。

时间复杂度\(O(n\log n)\),共做了一次多项式求逆,两次多项式乘法。

参考代码:

//problem:nflsoj550
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fst first
#define scd second

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

/*  ------  by:duyi  ------  */ // dysyn1314
const int MAXN=114514,MOD=998244353;
inline int mod1(int x){return x<MOD?x:x-MOD;}
inline int mod2(int x){return x<0?x+MOD:x;}
inline void add(int &x,int y){x=mod1(x+y);}
inline void sub(int &x,int y){x=mod2(x-y);}
inline int pow_mod(int x,int i){int y=1;while(i){if(i&1)y=(ll)y*x%MOD;x=(ll)x*x%MOD;i>>=1;}return y;}
int n,m,fac[MAXN+5],invf[MAXN+5];
void init(){
    fac[0]=1;
    for(int i=1;i<=MAXN;++i)fac[i]=(ll)fac[i-1]*i%MOD;
    invf[MAXN]=pow_mod(fac[MAXN],MOD-2);
    for(int i=MAXN-1;i>=0;--i)invf[i]=(ll)invf[i+1]*(i+1)%MOD;
}
inline int comb(int n,int k){
    if(n<k)return 0;
    return (ll)fac[n]*invf[k]%MOD*invf[n-k]%MOD;
}
int f[MAXN*4+5],g[MAXN*4+5],h[MAXN*4+5],rev[MAXN*4+5];
void NTT(int *a,int n,int flag){
    for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int i=1;i<n;i<<=1){
        int T=pow_mod(3,(MOD-1)/(i<<1));
        if(flag==-1) T=pow_mod(T,MOD-2);
        for(int j=0;j<n;j+=(i<<1)){
            for(int k=0,t=1;k<i;++k,t=(ll)t*T%MOD){
                int Nx=a[j+k],Ny=(ll)a[i+j+k]*t%MOD;
                a[j+k]=mod1(Nx+Ny);
                a[i+j+k]=mod2(Nx-Ny);
            }
        }
    }
    if(flag==-1){
        int invn=pow_mod(n,MOD-2);
        for(int i=0;i<n;++i)a[i]=(ll)a[i]*invn%MOD;
    }
}
void mul(int *a,int *b,int n,int m){
    // b <- a*b
    static int f[MAXN*4+5],g[MAXN*4+5];
    for(int i=0;i<n;++i)f[i]=a[i];
    for(int i=0;i<m;++i)g[i]=b[i];
    int lim=1,ct=0;
    while(lim<=n+m)lim<<=1,ct++;
    for(int i=n;i<lim;++i)f[i]=0;
    for(int i=m;i<lim;++i)g[i]=0;
    for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(ct-1));
    NTT(f,lim,1);
    NTT(g,lim,1);
    for(int i=0;i<lim;++i)f[i]=(ll)f[i]*g[i]%MOD;
    NTT(f,lim,-1);
    for(int i=0;i<n;++i)b[i]=f[i];
}
void _mul(int *a,int *b,int n,int m){
    // b <- 2b-a*b^2
    static int f[MAXN*4+5],g[MAXN*4+5];
    for(int i=0;i<n;++i)f[i]=a[i];
    for(int i=0;i<m;++i)g[i]=b[i];
    int lim=1,ct=0;
    while(lim<=(n*2))lim<<=1,ct++;
    for(int i=n;i<lim;++i)f[i]=0;
    for(int i=m;i<lim;++i)g[i]=0;
    for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(ct-1));
    NTT(f,lim,1);
    NTT(g,lim,1);
    for(int i=0;i<lim;++i)f[i]=mod2(mod1(g[i]*2)-(ll)f[i]*g[i]%MOD*g[i]%MOD);
    NTT(f,lim,-1);
    for(int i=0;i<n;++i)b[i]=f[i];
}
void get_inv(int *a,int n,int *res){
    if(n==1){
        res[0]=pow_mod(a[0],MOD-2);
        return;
    }
    int m=(n+1)>>1;
    get_inv(a,m,res);
    _mul(a,res,n,m);
}
int main() {
    init();
    scanf("%d%d",&n,&m);m%=MOD;
    for(int i=0,pw=1;i<n;++i){
        pw=(ll)pw*m%MOD;
        f[i]=(ll)pw*invf[i+1]%MOD;
        g[i]=invf[i+1];
    }
    get_inv(g,n,h);//h=g^{-1}
    mul(f,h,n,n);//h=f*h
    for(int i=0;i<n;++i)h[i]=(ll)h[i]*fac[i]%MOD;
    //for(int i=0;i<n;++i)cout<<h[i]<<" ";cout<<endl;
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    for(int k=0;k<n;++k)f[k]=(ll)pow_mod(m,n-k-1)*h[k]%MOD*comb(n,k+1)%MOD;//f[k]至少选k个的贡献
    //f[k] -> g[k](恰好选k个的贡献)
    for(int i=0;i<n;++i)f[i]=(ll)f[i]*fac[i]%MOD;
    for(int i=0;i<n;++i)h[i]=f[n-1-i];
    for(int i=0;i<n;++i)f[i]=h[i];
    for(int i=0;i<n;++i)if(i&1)g[i]=mod2(-invf[i]);else g[i]=invf[i];
    mul(f,g,n,n);
    for(int i=0;i<n;++i)h[i]=g[n-1-i];
    for(int i=0;i<n;++i)g[i]=(ll)h[i]*invf[i]%MOD;g[n]=0;
    for(int i=n-1;i>=1;--i)add(g[i],g[i+1]);
    for(int i=1;i<=n;++i)printf("%d ",g[i]);puts("");
    return 0;
}

题解 nflsoj550 【六校联合训练 省选 #9】序列的更多相关文章

  1. 题解 nflsoj553 【六校联合训练 省选 #10】飞

    题目链接 我们称"简要题意"给出的三个要求分别为"条件1","条件2","条件3". 条件3长得比较丑,考虑转化一下.把 ...

  2. NFLSOJ 1072 - 【2021 六校联合训练 NOIP #1】异或(FWT+插值)

    题面传送门 一道非常不错的 FWT+插值的题 %%%%%%%%%%%% 还是那句话,反正非六校的看不到题对吧((( 方便起见在下文中设 \(n=2^d\). 首先很明显的一点是这题涉及两个维度:异或和 ...

  3. NFLSOJ 1060 - 【2021 六校联合训练 NOI #40】白玉楼今天的饭(子集 ln)

    由于 NFLSOJ 题面上啥也没有就把题意贴这儿了( 没事儿,反正是上赛季的题,你们非六校学生看了就看了,况且看了你们也没地方交就是了 题意: 给你一张 \(n\) 个点 \(m\) 条边的图 \(G ...

  4. 题解 nflsoj489 【六校联合训练 CSP #15】小D与随机

    题目链接 考虑枚举好点的集合.此时要考虑的问题是如何填入\(1\sim n\)这些数使得恰好我们枚举到的这些点是好点,即:求出有多少种合法的填数方案. \(1\)号点一定是好点.那么除\(1\)号点外 ...

  5. HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)

    pid=5358">HDU 5358 题意: 求∑​i=1​n​​∑​j=i​n​​(⌊log​2​​S(i,j)⌋+1)∗(i+j). 思路: S(i,j) < 10^10 & ...

  6. 2017多校联合训练2—HDU6054--Is Derek lying?(思维题)

    Is Derek lying? Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  7. hdu 4649 Professor Tian 多校联合训练的题

    这题起初没读懂题意,悲剧啊,然后看了题解写完就AC了 题意是给一个N,然后给N+1个整数 接着给N个操作符(只有三种操作  即  或 ,与 ,和异或 |   &  ^ )这样依次把操作符插入整 ...

  8. HDU 4643 GSM 暑期多校联合训练第五场 1001

    点击打开链接 我就不说官方题解有多坑了 V图那么高端的玩意儿 被精度坑粗翔了 AC前 AC后 简直不敢相信 只能怪自己没注意题目For the distance d1 and d2, if fabs( ...

  9. 2017ACM暑期多校联合训练 - Team 8 1011 HDU 6143 Killer Names (容斥+排列组合,dp+整数快速幂)

    题目链接 Problem Description Galen Marek, codenamed Starkiller, was a male Human apprentice of the Sith ...

随机推荐

  1. lc 0222

    目录 ✅ 191. 位1的个数 描述 解答 cpp py ✅ 107. 二叉树的层次遍历 II 描述 解答 c todo 观赏 0222 py ✅ 806. 写字符串需要的行数 描述 解答 cpp j ...

  2. php 算法知识 冒泡排序

    function bubble_order($arr){ //得到长度 $count_num=count($arr); for($k=1;$k<$count_num;$k++){ //对长度越来 ...

  3. 笔记-python-standard library-8.3.collections

    笔记-python-standard library-8.3.collections 1.      collections简介 Source code: Lib/collections/__init ...

  4. 李德胜系列——李德胜和CPC人的初心

    很久很久以前,有三条恶龙盘踞着村庄,恶龙们及其爪牙对村民敲骨吸髓,逼着村民卖儿鬻女.苦不堪言.但是村民们却对此压迫习以为常,逆来顺受. 后来,一个书生来到了这个村庄,告诉村民,不许跪,也没有人值得他们 ...

  5. 靠谱的Pycharm安装详细教程

    如何在本机上下载和安装Pycharm,具体的教程如下: 1.首先去Pycharm官网,或者直接输入网址:http://www.jetbrains.com/pycharm/download/#secti ...

  6. windows 10 遥控操作和传输文件

    传输文件命令 scp file user@192.168.1.1:/home/           file文件传到192.168.1.1/home/目录下 scp -r directory user ...

  7. MySQL 之存储引擎与数据类型与数据约束

    一.存储引擎场景 1.InnoDB 用于事务处理应用程序,支持外键和行级锁.如果应用对事物的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包括很多更新和删除操作,那 ...

  8. 设计模式课程 设计模式精讲 8-3 单例设计模式-DoubleCheck双重检查实战及原理解析

    1 课程讲解 1.1 为何要使用双重检查 1.2 双重检查的缺点 1.3 指令重排序讲解 1.4 指令重排序比喻(自己理解) 1.5 如何解决指令重排序问题 2 代码演练 2.1 代码演练1(双重检查 ...

  9. Centos7 配置subversion

    CentOS7:配置SVN服务器 Posted on 2016-11-10 15:17 eastson 阅读(4266) 评论(0) 编辑 收藏 1. 安装 CentOS通过yum安装subversi ...

  10. win7 X64 进程名称不一致,导致杀进程失效!

    win7 x86, 或 win10 x64 环境下, x86的进程名称 ”aaa.exe“ 在win7 x64下面显示为  ”aaa.exe *32“