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. php安装php-redis扩展

    下载安装php-redis扩展: 地址:https://github.com/phpredis/phpredis/ $ wget http://pecl.php.net/get/redis-3.1.2 ...

  2. HTTP学习之HTTP基础

    学习HTTP技术,首先要了解它的在web通信中有哪些特点,起到什么作用.有哪些规范.都有什么功能. HTTP的特点 HTTP使用的是一种可靠的.快速响应的数据传输协议,用户一旦发起请求,Web服务器可 ...

  3. DVWA中SQL回显注入

    一.SQL注入简介 1.1 SQL语句就是操作数据库的语句,SQL注入就是通过web程序在数据库里执行任意SQL语句. SQL 注入是一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问和修改数据, ...

  4. STL——map和set

    一.map 1.map被定义为一对(pair即key和value)数值. key值在map内最多只有一份. 假如需要对一篇文章中的单词计数,那么就可以建立一个map,string类型的key,int型 ...

  5. 解决 Python2 和 Python3 的共存问题

    首先安装两种版本的Python 进入系统属性更改环境变量 将两个版本的安装路径找出. 添加至PATH中,变量之间用分号隔开. D:\Python36\Scripts\;D:\Python36\;D:\ ...

  6. (数据科学学习手札13)K-medoids聚类算法原理简介&Python与R的实现

    前几篇我们较为详细地介绍了K-means聚类法的实现方法和具体实战,这种方法虽然快速高效,是大规模数据聚类分析中首选的方法,但是它也有一些短板,比如在数据集中有脏数据时,由于其对每一个类的准则函数为平 ...

  7. phpMyAdmin出现错误 Access denied for user 'root'@'localhost' (using password: NO)

    今天安装wmpp,之后启动后点击phpMyAdmin 报拒绝连接错误:#1045 - Access denied for user 'root'@'localhost' (using password ...

  8. WPF中的ControlTemplate(控件模板)

    原文:WPF中的ControlTemplate(控件模板) WPF中的ControlTemplate(控件模板)                                             ...

  9. React实现最完整的百度搜索框

    import React,{Component} from 'react' import ReactDOM,{render} from 'react-dom' import 'bootstrap/di ...

  10. Sphinx与coreseek

    Sphinx : 高性能SQL全文检索引擎 分类 编程技术 Sphinx是一款基于SQL的高性能全文检索引擎,Sphinx的性能在众多全文检索引擎中也是数一数二的,利用Sphinx,我们可以完成比数据 ...