众所周知,排列是一个置换,一个置换是一车环。

步数就是这些环长的 \(lcm\)。

如果你去思考直接 DP,会发现很困难,根本设不出来状态。于是考虑正难则反:每个质数幂 \(p^k\) 对答案的贡献。

可以发现,如果设 \(f[p^k]\) 是 \(p^k\) 在 \(f[p^k]\) 个排列的 \(lcm\) 中出现过,那么答案是 \(\sum_{p^k\leq n}p^{f[p^k]}\)。

考虑去计算这个 \(f\)。计算出现过似乎也很困难,正难则反计算没出现过的。(后文令 \(t=p^k\))

然后有一个显然的 DP:设 \(dp[n]\) 为 \(n\) 个元素构成的置换群中,没有一个环的长度是 \(t\) 的倍数。那么似乎只需要从非 \(t\) 的倍数转移过来就可以了。

但是我们并不会计算新加入若干个元素会产生多少个新排列。考虑原本有 \(n\) 个元素的情况下加入了一个大小为 \(m\) 的环。

我们强制钦定 \(1\) 必须在这个环中,那么我们还需要从 \([2,n+m]\) 中选出 \([m-1]\) 个数,然后有 \((m-1)!\) 种不同的排列方式。所以方案数乘上了 \(\binom{n+m-1}{m-1}(m-1)!=\frac{(n+m-1)!}{n!}\)。

然后我们好像会了 \(O(n^3)\) 计算这个玩意儿(

考虑优化,正难则反。我们不计算非 \(t\) 倍数位置转移过来的值,考虑维护前面所有位置转移过来的值减去 \(t\) 倍数转移过来的值。这个是很好维护的。

于是做到了 \(O(n^2)\)。

#include<cstdio>
typedef unsigned ui;
typedef __uint128_t LL;
typedef unsigned long long ull;
const ui M=7505;
struct Barrett{
ull m,b;
Barrett(const ui&m=1):m(m),b(((LL(1)<<80)+m-1)/m){}
friend inline ull operator%(const ull&a,const Barrett&mod){
return a-mod.m*(LL(mod.b)*a>>80);
}
}mod,MOD;
ui n,m,tm,TM,c[M],S[M],dp[M],minp[M];
inline ui pow(ui a,ui b){
ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
signed main(){
ui ans(1),fac(1);
scanf("%u%u",&n,&m);minp[1]=1;
mod=Barrett(tm=m);MOD=Barrett(TM=m-1);
for(ui i=1;i<=n;++i)c[i]=1,fac=1ull*fac*i%MOD;
for(ui i=2;i<=n;++i)if(!minp[i]){
for(ui j=i*i;j<=n;j+=i)minp[j]=1;
for(ui j=i;j<=n;j*=i)minp[j]=i;
}
for(ui i=2;i<=n;++i){
for(ui j=1;j+i-1<=n;++j)c[j]=1ull*c[j]*(i+j-2)%MOD;
if(minp[i]<=1)continue;
const ui&pk=i;ui sum(1);
dp[0]=1;S[0]=1;
for(ui i=1;i<=n;++i){
if(pk<=i)S[i]=1ull*S[i-pk]*c[i-pk+1]%MOD;else S[i]=0;
dp[i]=(TM+sum-S[i])%MOD;
S[i]=(1ull*S[i]*i+dp[i])%MOD;
sum=(1ull*sum*i+dp[i])%MOD;
}
ans=1ull*ans*pow(minp[i],TM+fac-dp[n])%mod;
}
printf("%u",ans);
}

但是这样真的够快吗?

考虑生成函数。

置换是一个典型的有标号计数问题。只需要计算出一个环的 EGF 再将其 \(\exp\) 即可。

而一个环的 EGF 显然是 \(\sum_{i=1}\frac{(i-1)!}{i!}x^i-\sum_{i=1}\frac{(it-1)!}{(it)!}x^{it}\)。

\[\exp(\sum_{i=1}\frac{(i-1)!}{i!}x^i-\sum_{i=1}\frac{(it-1)!}{(it)!}x^{it})
\]
\[\exp(\sum_{i=1}\frac{1}{i}x^i-\sum_{i=1}\frac{1}{it}x^{it})
\]
\[\exp(-\ln(1-x)+\frac{1}{t}\ln(1-x^{t}))
\]
\[\frac{(1-x^t)^{\frac{1}{t}}}{1-x}
\]

注意到 \(\frac{1}{1-x}\) 是前缀和,分子又只在 \(t\) 的倍数处有值,所以可以考虑改写一下这个东西:

\[[\frac{x^n}{n!}]\frac{(1-x^{t})^{\frac{1}{t}}}{1-x}
\]
\[[\frac{x^n}{n!}]\frac{(1-x^{t})^{\frac{1}{t}}}{1-x^{t}}
\]
\[n![x^{\lfloor\frac{n}{t}\rfloor}](1-x)^{\frac{1}{t}-1}
\]

剩下的就交给广义二项式定理吧。

设 \(m=\lfloor\frac{n}{t}\rfloor\):

\[n!\binom{\frac{1}{t}-1}{m!}(-1)^{m}
\]
\[n!\prod_{i=1}^{m}-\frac{\frac{1}{t}-1-i+1}{i}
\]
\[n!\prod_{i=1}^{m}\frac{it-1}{it}
\]

但是这个是在指数上做的,所以模数并不是质数。

注意到这个 \(it\) 将 \(n!\) 分成了 \(m+1\) 段,可以将 \(n!\) 看做一个序列,我们只需要支持查询区间乘积即可。

使用猫树可以做到 \(O(n\log n)\) 的复杂度。

#include<cstdio>
typedef unsigned ui;
typedef __uint128_t LL;
typedef unsigned long long ull;
const ui M=7505;
ui n,m,minp[M];
struct Barrett{
ull m,b;
Barrett(const ui&m=1):m(m),b(((LL(1)<<80)+m-1)/m){}
friend inline ull operator%(const ull&a,const Barrett&mod){
return a-mod.m*(LL(mod.b)*a>>80);
}
}mod,MOD;
struct DS{
ui D,len,lg[8192],prod[15][8192];
inline void init(const ui&n){
D=0;len=1;
while((1<<D)<=n)++D,len<<=1;
for(ui i=1;i<=len;++i)prod[0][i]=i;
for(ui i=1;i<=len;++i)lg[i]=lg[i>>1]+1;
for(ui d=1;d<=D;++d){
for(ui k=1;k<=(len>>d);++k){
const ui&L=k-1<<d,&R=k<<d,&mid=L+R>>1;
prod[d][mid]=mid;prod[d][mid+1]=mid+1;
for(ui i=mid-1;i>=L+1;--i)prod[d][i]=1ull*prod[d][i+1]*i%MOD;
for(ui i=mid+1+1;i<=R;++i)prod[d][i]=1ull*prod[d][i-1]*i%MOD;
}
}
}
inline ui operator()(const ui&L,const ui&R){
if(L>R)return 1;if(L==R)return L;
ui d=lg[L-1^R-1];return 1ull*prod[d][L]*prod[d][R]%MOD;
}
}SGT;
inline ui pow(ui a,ui b){
ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
inline ui Solve(const ui&k){
const ui&m=n/k;ui ans;ans=SGT(m*k+1,n);
for(ui i=1;i<=m;++i)ans=1ull*ans*SGT((i-1)*k+1,i*k-1)%MOD,ans=1ull*ans*(i*k-1)%MOD;
return ans;
}
signed main(){
ui ans(1),fac(1);
scanf("%u%u",&n,&m);
mod=Barrett(m);MOD=Barrett(m-1);SGT.init(n);
for(ui i=1;i<=n;++i)fac=1ull*fac*i%MOD;
for(ui i=2;i<=n;++i){
if(!minp[i]){
for(ui j=i*i;j<=n;j+=i)minp[j]=1;
for(ui j=i;j<=n;j*=i)minp[j]=i;
}
if(minp[i]>1)ans=1ull*ans*pow(minp[i],m-1+fac-Solve(i))%mod;
}
printf("%u",ans);
}

LGP6276题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. js 对象的深克隆

    前端笔试或者面试的时候,很喜欢问的一个问题就是对象的深度克隆,或者说是对象的深度复制.其实这个问题说容易很容易,但是要说全面也挺不易. 要弄明白对象的克隆,首先要明白js中对象的组成.在js中一切实例 ...

  2. FidBugs的使用学习

    是什么? 静态代码分析器,它检查类或者JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题.Findbugs自带检测器,其中有60余种Bad practice,80余种Correctness, ...

  3. Spring Cloud 源码分析之OpenFeign

    OpenFeign是一个远程客户端请求代理,它的基本作用是让开发者能够以面向接口的方式来实现远程调用,从而屏蔽底层通信的复杂性,它的具体原理如下图所示. 在今天的内容中,我们需要详细分析OpenFei ...

  4. shell——并发工具parallel

    官方文档:https://www.gnu.org/software/parallel/parallel_tutorial.html 安装 (wget -O - pi.dk/3 || curl pi.d ...

  5. LVS调度算法总结

    LVS 调试算法分为两种:静态方法和动态方法. 静态方法 RR:轮询 WRR:加权轮询 SH:源地址哈希,将来自于同一个IP地址的请求始终发往第一次挑中的RS,从而实现会话绑定 DH:目标地址哈希,第 ...

  6. linux_4

    自建yum仓库,分别为网络源和本地源 编译安装http2.4 linux命令练习 列出ubuntu软件管理工具apt的一些用法(自由总结)

  7. 虫师Selenium2+Python_7、unittest单元测试框架

    P173--通过unittest单元测试框架别写测试用例 from calculator import Count import unittest   class TestCount(unittest ...

  8. netty系列之:让TCP连接快一点,再快一点

    简介 经典的TCP三次握手大家应该很熟悉了,三次握手按道理说应该是最优的方案了,当然这是对于通用的情况来说的.那么在某些特殊的情况下是不是可以提升TCP建立连接的速度呢? 答案是肯定的,这就是今天我们 ...

  9. ScaleFlux CSD 2000 在携程的应用实践

    一.业界背景与现状 近些年来,有三件事实在业界同时发生:     1.  业务的发展朝着"生产"和"使用"海量增长数据的方向演进.     2.  摩尔定律 的 ...

  10. 打造一款属于自己的CentOS操作系统

    文章目录 声明 关闭selinux以及firewalld 修改终端前缀显示 修改默认网卡名称为eth0 替换yum源 安装常用工具 优化history 配置回收站 迎宾显示 优化vim 清空yum缓存 ...