[POI2008]PER-Permutation
[POI2008]PER-Permutation 带重复的康托展开!
根本不需要中国剩余定理就可以A掉!
看完题面你会惊人地发现这好像一个康托展开!(显然是不同的啦)
首先我们来看康托展开这个东西在数组为排列时怎么打
------->度娘
int cantor(int a[],int n){//cantor展开,n表示是n位的全排列,a[]表示全排列的数(用数组表示)
int ans=0,sum=0;
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++)
if(a[j]<a[i])
sum++;
ans+=sum*factorial[n-i];//累积
sum=0;//计数器归零
}
return ans+1;
}
对于每一个数算出贡献,贡献为后面出现的比它小的数(设w个即这一位本来还可以选的数)乘上后面数个数的阶乘
这个w显然可以用树状数组优化
由于后面的数会出现重复,所以我们对于那些重复的数(假设出现了k次),他们会被枚举出\(k!\)种排列,我们要把它除掉
所以这个数\(a[i]\)的贡献为
\]
\(cnt[j]\)表示i~n这一段中每个数 j 出现的个数
对于这个分母,显然不可以高精!我们会自然想到模逆元,但模逆元也是要求互质的!那怎么办?
把\(m\)的因数在答案中出现的提出来,不就互质了吗!(也就是在每次计算时把这些因子除掉,记录提出因子的个数)
由于对于上面的式子 \(\frac{(n-i)!}{\Pi \ {cnt[j]!}}\)
这个东西显然是个整数,(你可以像证明组合数是个整数一样证明它),所以上面的因子个数-下面这些因子的个数显然是自然数,提出来后把剩下的答案乘出来,最后再把那些多出来的因子乘上去就行了
tips:因为模数不是质数,故不能用费马
(你可以看一下我丑陋的code)
typedef long long ll;
#define reg register
#define rep(a,b,c) for(int a=b,a##end=c;a<=a##end;++a)
#define drep(a,b,c) for(int a=b,a##end=c;a>=a##end;--a)
const int N=3e5+10;
int n,m;
void Exgcd(ll a,ll b,ll &x,ll &y){
if(b==0) { x=1,y=0; return ;}
Exgcd(b,a%b,y,x);
y-=a/b*x;
}
inline ll Inv(ll x,ll P){
ll a,b;
Exgcd(x,P,a,b);
return (a%P+P)%P;
}
int a[N];
struct BIT{
ll s[N];
void init(){ memset(s,0,sizeof s); }
void Add(int p,int x){
while(p<N) s[p]+=x,p+=p&-p;
}
ll Que(int p){
int res=0;
while(p) res+=s[p],p^=p&-p;
return res;
}
}Bit;
//树状数组用来求大于i小于a[i]的个数
int c[N],cc[N];
ll fac[N],fcnt,b[N],pq[N];
ll po[50][N];
int cnt[50];
//cnt记录m的每一个因数被提出来的个数
void Count(ll &x,int k){
rep(i,1,fcnt){
int p=fac[i];
while(x%p==0) {
x/=p;
cnt[i]+=k;
}
}
}
ll Get(){
ll res=1;
rep(i,1,fcnt) (res*=po[i][min(cc[i],cnt[i])])%=m;
return res;
}
ll Solve(){
ll ans=1,res=1;
c[a[n]]=1,Bit.Add(a[n],1);
drep(i,n-1,1){
ll t=n-i;
Count(t,1);//计算(n-i)!要多乘上的值,也提出m的因数
(res*=t)%=m;
t=++c[a[i]];//计算分子中变化的值,提出其中m的因数
//这两步保证了求逆元时一定是互质有解的
Count(t,-1);
(res*=Inv(t,m))%=m;
Bit.Add(a[i],1);
t=Get();//计算提出因数的总乘积
(ans+=res*Bit.Que(a[i]-1)%m*t%m)%=m;
//套入计算公式
}
return ans;
}
int main(){
n=rd(),m=rd();
rep(i,1,n) a[i]=rd();
int tmp=m;
for(int i=2;(i*i)<=tmp;i++) if(tmp%i==0){
fac[++fcnt]=i;
po[fcnt][0]=1;
rep(j,1,N-1) po[fcnt][j]=po[fcnt][j-1]*i%m,cc[fcnt]++;
while(tmp%i==0) tmp/=i;
}
if(tmp>1) {
fac[++fcnt]=tmp;
po[fcnt][0]=1;
rep(j,1,N-1) po[fcnt][j]=po[fcnt][j-1]*tmp%m,cc[fcnt]++;
}
//处理出m的因数,预处理次方
printf("%lld\n",Solve());
}
[POI2008]PER-Permutation的更多相关文章
- 洛谷 P3477 [POI2008]PER-Permutation 解题报告
P3477 [POI2008]PER-Permutation 题目描述 Multiset is a mathematical object similar to a set, but each mem ...
- Permutation Sequence
The set [1,2,3,-,n] contains a total of n! unique permutations. By listing and labeling all of the p ...
- [LeetCode] Palindrome Permutation II 回文全排列之二
Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...
- [LeetCode] Palindrome Permutation 回文全排列
Given a string, determine if a permutation of the string could form a palindrome. For example," ...
- [LeetCode] Permutation Sequence 序列排序
The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...
- [LeetCode] Next Permutation 下一个排列
Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...
- Leetcode 60. Permutation Sequence
The set [1,2,3,-,n] contains a total of n! unique permutations. By listing and labeling all of the p ...
- UVA11525 Permutation[康托展开 树状数组求第k小值]
UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...
- Permutation test: p, CI, CI of P 置换检验相关统计量的计算
For research purpose, I've read a lot materials on permutation test issue. Here is a summary. Should ...
- [BZOJ1112][POI2008]砖块Klo
[BZOJ1112][POI2008]砖块Klo 试题描述 N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另 ...
随机推荐
- Jemeter学习环境部署。
本文档中所有软件的下载地址 链接:https://pan.baidu.com/s/1RREUwlH7GtYMUWeiRjtWVg 提取码:zmjy 一.安装jdk 下载网盘中的jdk 双击jdk-8u ...
- 给基于对话框的MFC程序添加状态栏并实时显示时间
转载自丝雪儿 1.首先在string table 里添加两个字串,ID分别为IDS_INDICATOR_MESSAGE and IDS_INDICATOR_TIME 2.在你的 dlg.h 类里面加个 ...
- 虚拟机安装mysql踩坑记录
本章节主要讲解的是在虚拟机centOs7版本以上安装mysql5.6版本,亲测可以直接使用,有需要帮助的小伙伴可以加本人QQ2246451792@qq.com!!!! 卸载centOs7自带的mari ...
- svn进行上传项目
当svn的服务器搭建成功后,就可以进行上传项目了. 右键,选择客户端的repo-browser, 输入地址 然后就可以浏览所有项目: 然后在版本仓库上,右键,add folder, 添加对应的文件夹即 ...
- nginx配置ssl证书流程及常见问题
背景: 项目开发中用到了微信小程序,但是服务器配置URL必须是HTTPS,所以需要通过配置nginx的SSL模块来支持HTTPS访问,也就是说,要做一个网站域名为 dmsdbj.com ...
- java标识符的作用和命名规则
今天让我们从心开始学习Java,从最基础的开始. 这篇先从java标识符的作用和命名规则说起. 1.作用 常量.变量.方法.类和包等的名称. 2.命名规则 必须以字母._下划线.美元符$开头. 其他部 ...
- 详解Linux操作系统的进程
系统 计算机运行起来以后,就是由内核和运行在内核之上的众多进程来实现的(kernel+process) 内存分为 : 线性内存: 物理内存: 计算机的所有运行都只在内存和CPU中运行! 内核空间 ...
- The Preliminary Contest for ICPC Asia Nanjing 2019 H. Holy Grail
题目链接:https://nanti.jisuanke.com/t/41305 题目说的很明白...只需要反向跑spfa然后输入-dis,然后添-dis的一条边就好了... #include < ...
- 调试用Chrome浏览器
今天写HTML页面调试时出了问题:一个页面在本地的工作空间文件夹内可以打得开,在HBuilder里用Edge打不开. 我还以为是工作空间路径出问题了,重建了好几次空间和项目.. 询问了小页,他建议以后 ...
- django项目中使用邮箱找回密码功能
本文使用qq邮箱,需要登录邮箱,在设置-账户里面开启SMTP服务,要记下授权码 前端html {#找回密码的表单#} <form action="" method=" ...