P3477 [POI2008]PER-Permutation

题目描述

Multiset is a mathematical object similar to a set, but each member of a multiset may have more than one membership.

Just as with any set, the members of a multiset can be ordered in many ways. We call each such ordering a permutation of the multiset. For example, among the permutations of the multiset{1,1,2,3,3,3,7,8}. there are {2,3,1,3,3,7,1,8} and{8,7,3,3,3,2,1,1}.

We will say that one permutation of a given multiset is smaller (in lexicographic order) than another permutation, if on the first position that does not match the first permutation has a smaller element than the other one. All permutations of a given multiset can be numbered (starting from one) in an increasing order.

Task Write a programme that reads the description of a permutation of a multiset and a positive integerm from the standard input, determines the remainder of the rank of that permutation in the lexicographic ordering modulo m, writes out the result to the standard output.

多重集合是数学中的一个概念,它的定义很像集合,但是在多重集之中,同一个元素可以出现多次。

和集合一样,多重集的的元素可以有很多种元素的排布顺序。我们把它叫作多重集的排列。

现在我们定义多重集的某个排列\(s_i\)比某个排列\(s_j\)的大小比较为字典序比较。这样某个多重集的排列可以从小到大得排起来。

现在给你一个元素个数为n的多重集的一个排列和\(m\),求这个排列的排名取模\(m\)。

输入输出格式

输入格式:

The first line of the standard input holds two integers n( \(1\le n \le 300000\)) and m ( \(2 \le m \le 10^9\)) ,separated by a single space. These denote, respectively, the cardinality of the multiset and \dots\ the number m.

The second line of the standard input contains n positive integers \(a_i\) (\(1\le a_i \le 300000\)), separated by single spaces and denoting successive elements of the multiset permutation.

第一行 两个整数n,m

第二行 n个数,代表多重集的排列

输出格式:

The first and only line of the standard output is to hold one integer, the remainder modulo m of the rank of the input permutation in the lexicographic ordering.

一行一个整数 排名取模m


一句话题意:求有重复元素的排列的排名,模数不一定是质数

我们找到字典序比它小的排列的个数

讨论每一位数值的贡献,像康托展开那样

设给出排列为 \(a_1,a_2,a_3,...a_n\),字典序比它小的排列为\(b_1,b_2,b_3,...b_n\)

考虑从左到右第\(i\)位的贡献

若\(b_i=a_i\) 右边的是子问题

若\(b_i<a_i\),则设右边的从小到大每个元素出现的次数分别为\(c_1,c_2,...,c_m\)

若\(b_i\)出现\(c_j\)次

则当\(b_i\)这个数值放在第\(i\)位置,右边的全排列的贡献为

\(\frac{(n-i)!}{c_1! \times c_2 ! \times ... \times c_m!} \times c_j\)

则所有可以放到第一位的数的贡献和为

\(\frac{(n-i)!}{c_1! \times c_2 ! \times ... \times c_m!} \times \sum_{b_i<a_i}c_j\)(\(b_i\)这里代表数值意义,一个数值只出现一次)

我们处理每一位这样的

后面的好处理,树状数组维护一下就行了

前面的因为模数不为质数可能没有逆元,所有我们先把模数唯一分解,对每一个质因子的多少次方做,然后CRT进行合并

在某个质因子多少次方下做时,我们把数字拆成 其他项 和 这个质因子多少次方 就行了

因为答案一定是整数,所以分子的质因子个数一定大于分母的,我们把这些先拿出来,就可以求逆元啦,然后快速幂乘回去就行

注意小细节


Code:

#include <cstdio>
#include <cstring>
#define ll long long
const int N=3e5+10;
ll a[N],m,n,buct[N],id[N],cnt0[N];
ll fac[N],ct[N],mx,sum[N],mod;
void exgcd(ll a,ll b,ll &x,ll &y)//只是一个exgcd..
{
if(!b){x=1,y=0;return;}
exgcd(b,a%b,x,y);
ll tmp=x;
x=y;
y=tmp-a/b*y;
}
ll inv(ll a,ll p)//只是一个求逆元
{
ll x,y;
exgcd(a,p,x,y);
return (x%p+p)%p;
}
ll CRT(ll a,ll b)//只是CRT的一项
{
return mod/b*a%mod*inv(mod/b,b)%mod;
}
ll quick_pow(ll d,ll k,ll p)//只是一个快速幂
{
ll f=1;
while(k)
{
if(k&1) f=f*d%p;
d=d*d%p;
k>>=1;
}
return f;
}
ll query(ll x)
{
ll s;for(s=0;x;x-=x&-x) s+=sum[x];
return s;
}
void add(ll x)
{
while(x<=m) ++sum[x],x+=x&-x;
}
ll cal(ll d,ll p)
{
ll ans=0;fac[0]=1;
memset(ct,0,sizeof(ct));
for(ll i=1;i<=mx;i++)
{
ll num=i;
while(num%d==0) num/=d;
(fac[i]=fac[i-1]*num%p)%=p;
for(ll j=i;j;j/=d) ct[i]+=j/d;
}
memset(cnt0,0,sizeof(cnt0));
memset(sum,0,sizeof(sum));
cnt0[a[n]]++;add(a[n]);
ll den=1,cn=0;
for(ll i=n-1;i;i--)
{
ll cc=++cnt0[a[i]];
add(a[i]);
if(cc>1)
{
(den*=fac[cc-1]*inv(fac[cc],p)%p)%=p;
cn+=ct[cc]-ct[cc-1];
}
ll k=query(a[i]-1);
(ans+=fac[n-i]*den%p*k%p*(k?quick_pow(d,ct[n-i]-cn,p):0)%p)%=p;
}
return ans;
}
ll calp(ll p)
{
ll ans=0;
fac[0]=1;
for(ll i=1;i<=mx;i++)
fac[i]=(fac[i-1]*i)%p;
memset(cnt0,0,sizeof(cnt0));
memset(sum,0,sizeof(sum));
cnt0[a[n]]++;add(a[n]);
ll den=1;
for(ll i=n-1;i;i--)
{
ll cc=++cnt0[a[i]];
add(a[i]);
if(cc>1) (den*=fac[cc-1]*inv(fac[cc],p)%p)%=p;
(ans+=fac[n-i]*den%p*query(a[i]-1)%p)%=p;
}
return ans;
}
ll work(ll p)
{
ll ans=0;
for(ll i=2;i*i<=p;i++)
{
if(p%i==0)
{
ll d=1;
while(p%i==0)
p/=i,d*=i;
if(i==d)
(ans+=CRT(calp(i)+1,p))%=mod;
else
(ans+=CRT(cal(i,d)+1,d))%=mod;
}
}
if(p!=1) (ans+=CRT(calp(p)+1,p))%=mod;
return ans;
}
int main()
{
//freopen("data.in","r",stdin);
scanf("%lld%lld",&n,&mod);
for(ll i=1;i<=n;i++) scanf("%lld",a+i),buct[a[i]]++;
for(ll i=1;i<=N-10;i++) if(buct[i]) id[i]=++m;
for(ll i=1;i<=n;i++)
{
mx=mx>buct[a[i]]?mx:buct[a[i]];
a[i]=id[a[i]];
}
mx=mx>n?mx:n;
printf("%lld\n",work(mod));
return 0;
}

2018.8.27

洛谷 P3477 [POI2008]PER-Permutation 解题报告的更多相关文章

  1. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  2. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  3. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  4. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  5. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  6. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

  7. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  8. NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告

    前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享. 题目大意: 给一棵无根树,给出m条路径.允许将树上的一条边的权值改为0.求m条路径长度最大值的最小值.n,m< ...

  9. 洛谷 P1129 [ZJOI2007]矩阵游戏 解题报告

    P1129 [ZJOI2007]矩阵游戏 题目描述 小\(Q\)是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个\(N*N\)黑白方阵进行(如同国际象棋一般 ...

随机推荐

  1. 虚拟环境管理之virtualenvwrapper

    上一篇写了下在linux上使用python的虚拟环境, 干脆把virtualenvwrapper也写一下 1.为什么要用virtualenvwrapper virtualenv 的一个最大的缺点就是: ...

  2. php Trait的使用

    1.php中的trait是啥? 看上去既像类又像接口,其实都不是,Trait可以看做类的部分实现,可以混入一个或多个现有的PHP类中,其作用有两个:表明类可以做什么:提供模块化实现.Trait是一种代 ...

  3. python练习笔记

    python练习笔记,装饰器.定制方法生成特定的类 # -*- coding: utf-8 -*- def catch_exception(func): def wrap(self, *args, * ...

  4. Hadoop(24)-Hadoop优化

    1. MapReduce 跑得慢的原因 优化方法 MapReduce优化方法主要从六个方面考虑:数据输入.Map阶段.Reduce阶段.IO传输.数据倾斜问题和常用的调优参数. 数据输入 Map阶段 ...

  5. 中恳中笨 搭建flask封装环境

    话不多说,先干再说..... 打开pycharm,创建一个关于flask的项目 2.创建一个App的文件包 3.把staic和templates文件包拖进App里 4.把app.py文件改为manag ...

  6. WordPress4.9 最新版本网站安全漏洞详情与修复

    wordpress 目前互联网的市场占有率较高,许多站长以及建站公司都在使用这套开源的博客建站系统来设计网站,wordpress的优化以及html静态化,深受google以及搜索引擎的喜欢,全世界大约 ...

  7. SAN---第二网的概念

    网络技术的优缺点:优点:连接能力,超强路由,管理能力,远距离缺点:低速以及高负载,强烈的软件需求,错误检测能力 SAN:storage area network(存储区域网络)--是一种基于光网的特殊 ...

  8. Java8新特性(二)——强大的Stream API

    一.强大的Stream API 除了Lambda表达式外,Java8另外一项重大更新便是位于java.util.stream.*下的Stream API Stream 是 Java8 中处理集合的关键 ...

  9. asp.net MVC+easyUI 文件上传

    前言:公司前端都是index页面引用js,剩下的添加...都是html页.加大操作难度5555,所以就是主页面操作子页面上传.效果如下: 1,前端html页代码如下 .其中请注意,form中encty ...

  10. vs2015-Cordova开发安卓应用环境搭建

    之前看到过用html5+css+js就可以开发跨平台的应用,然后发现vs2015里就有个Cordova项目所以就想试试,但并不是这么顺利.刚开始对安卓环境一点也不了解,就到处百度搜索.终于成功了. 首 ...