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

步数就是这些环长的 \(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. linux中vim编辑器三种模式及常用命令的使用

    Linux命令经常使用才会烂熟于心 命令行模式: 移动光标: 向下左右箭头可以移动光标: 将光标移动到行尾:$; 将光标移动到行头:^: 将光标移动到页尾:shift+g; 将光标移动到页头:1+sh ...

  2. Centos下安装配置WordPress与nginx教程

    感谢大佬:https://www.howtoing.com/how-to-install-wordpress-with-nginx-on-centos-6-2 WordPress是一个免费和开源网站和 ...

  3. Note/Solution - 转置原理 & 多点求值

    \[\newcommand{\vct}[1]{\boldsymbol{#1}} \newcommand{\mat}[1]{\begin{bmatrix}#1\end{bmatrix}} \newcom ...

  4. Solution -「LOJ #150」挑战多项式 ||「模板」多项式全家桶

    \(\mathcal{Description}\)   Link.   给定 \(n\) 次多项式 \(F(x)\),在模 \(998244353\) 意义下求 \[G(x)\equiv\left\{ ...

  5. Solution -「CF 1392G」Omkar and Pies

    \(\mathcal{Description}\)   Link.   给定两个长度为 \(K\) 的 \(01\) 串 \(S,T\) 和 \(n\) 组操作 \((a_i,b_i)\),意义为交换 ...

  6. 4.2 K8S超级完整安装配置

    前言: 采坑 k8s有3种安装方式,如下所示: minikube:这是一个k8s集群模拟器,只有一个节点的集群,只为了测试使用,master和node都在一台机器上 直接使用带有容器功能的云平台安装: ...

  7. 性能测试:k8s集群监控环境搭建(kube-prometheus)

    选择kube-prometheus版本 k8s集群版本是1.22.x 5个节点 说明:如果你电脑配置低,也可以1个master节点,2个node节点 3个节点 Kube-Prometheus地址:ht ...

  8. RENIX报文字段跳变——网络测试仪实操

    什么是报文字段跳变? 报文字段跳变是指字段的值进行一些列有规则的变化,Renix支持对字段进行递增.递减.列表和随机变化. 如当用户想要仿真大量的源IP变化的数据时,就可以使用Modifier进行规则 ...

  9. ISISv6协议测试——信而泰网络测试仪实操

    文章关键词 ISIS协议:路由协议:协议测试: 一.前言: isis是一种与ospf很相似的网络协议(属于动态路由协议),它被应用在巨大规模网络,如运营商以及银行等.同样的它也是基于链路状态算法,支持 ...

  10. eBPF会成为服务网格的未来吗?

    服务网格现状 服务网格为服务提供了复杂的应用层网络管理,如服务发现.流量路由.弹性(超时/重试/断路).认证/授权.可观察性(日志/度量/追踪)等. 在分布式应用的早期,这些要求是通过直接将所需的逻辑 ...