洛谷P1521 求逆序对 题解

题意:

  求1到n的全排列中有m对逆序对的方案数。

思路:

  1.f[i][j]表示1到i的全排列中有j对逆序对的方案数。
  2.显然,1到i的全排列最多有(i-1)*i/2对逆序对,而对于f[i][j]来说,新加入一个数i+1,产生的新的逆序对数与插入的位置有关(数目为插入的数的位置之后的数的数目),于是n^4暴力就新鲜出炉了。
  3.换一个角度来说,当i>j的时候,我们枚举i的全排列的第一位的数字,如果是1,那么就要求剩下i-1个数中有j个全排列,如果是2,要求剩下i-1个数中有i-2个
全排列,依次类推,得到了第一个方程:f[i][j]=sum{f[i-1][0],f[i-1][1],f[i-1][2].....f[i-1][j]}
    当i<=j的时候,由于i的全排列中最大的数字是i,所以把i放到第一位上,由第一位最多能能产生i-1个逆序对,把1放到第一位上能产生0个逆序对,所以i-1-1+1=i-1,这时的f[i][j]就要由f[i-1][j]开始算上他自己,总共i-1项的和。因此:f[i][j]=sum{f[i-1][j],f[i-1][j-1],f[i-1][j-2].....f[i-1][j-i+1]}

反思:

  我只会暴力,优化只能理性愉悦一下了,好菜啊……

代码:

  n^4暴力:

 1 #include<cstdio>
 2 int n,m,i,j,k,f[201][10000];
 3
 4 int main()
 5 {
 6     scanf("%d%d",&n,&m);
 7     f[1][0]=1;
 8     for (i=1;i<n;++i)
 9         for (j=0;j<=(i-1)*i>>1;++j)
10             for (k=0;k<=i;++k)
11                 if ((f[i+1][j+i-k]+=f[i][j])>=10000) f[i+1][j+i-k]-=10000;
12     printf("%d\n",f[n][m]);
13     return 0;
14 }

  n^3:

 1 #include<cstdio>
 2 int n,m,i,j,f[101][5000];
 3
 4 int main()
 5 {
 6     scanf("%d%d",&n,&m);
 7     f[1][0]=1;
 8     for (i=2;i<=n;++i)
 9     {
10         for (j=0;j<i;++j) f[i][j]=(f[i][j-1]+f[i-1][j])%10000;//因为f[i,j]里面统计的是类似于前缀和的一个东西,f[i][j]只比f[i][j-1]多了f[i-1][j]这一项
11         for (;j<=(i-1)*i>>2;++j) f[i][j]=(f[i][j-1]+f[i-1][j]-f[i-1][j-i])%10000;//这时求和的项数确定了,就是i-1项,于是f[i,j]比f[i][j-1]多了f[i-1][j]这一项,少了f[i-1][j-i]这一项
12         for (;j<=(i-1)*i>>1;++j) f[i][j]=f[i][((i-1)*i>>1)-j];//因为数对总数为i*(i-1)/2,而一个数对要么是逆序对要么是顺序对,因此f[i][j]是关于f[i][i*(i-1)/4]呈现中心对称的
13     }
14     printf("%d\n",(f[n][m]+10000)%10000);
15     return 0;
16 }
时间: 2024-11-06 23:34:45

洛谷P1521 求逆序对 题解的相关文章

洛谷P1908 求逆序对 [归并排序]

题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游 戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. 输入输出格式 输入格式: 第一行,一个数n,表示序列中有n个数. 第二行n个数,表示给定的序列. 输出格式: 给定序列中逆序对的数目. 输入输出样例

洛谷P2513 [HAOI2009]逆序对数列

P2513 [HAOI2009]逆序对数列 题目描述 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? 输入输出格式 输入格式: 第一行为两个整数n,k. 输出格式: 写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果. 输入输出样例 输入样例#1: 4 1 输出样例#1: 3 说明 样例说明:

【洛谷P2513】逆序对数列

前缀和.滚动数组优化dp f[i][j]表示前i个数,逆序对数为j的方案数 我们知道,在第k个位置放第i个数,单步得到的逆序对数为i-k 则在前i个数,最多能产生的逆序对数为i个,最少0个,均可转移到j 所以我们得到:f[i][j]=sum(f[i-1][j...j-i]) 所以我们可以通过前缀和优化j 滚动数组消去 i 的一维 这样时间复杂度由n^2k变为nk,空间由nk变为k 1 #include<cstdio> 2 #include<cstring> 3 using name

洛谷P1774 最接近神的人_NOI导刊2010提高(02)(求逆序对)

To 洛谷.1774 最接近神的人 题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着“神的殿堂”.小FF猜想里面应该就有王室的遗产了.但现在的问题是如何打开这扇门…… 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的.而最聪明的人往往通过一种仪式选拔出来.仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元

归并排序求逆序对 //(洛谷)U4566 赛车比赛

https://www.luogu.org/problem/show?pid=U4566 显然的逆序对,以前只是嘴巴ac,这次终于打了出来. 逆序对其实就是冒泡排序的排序次数....但是一般的排序时间复杂度为O(n^2),于是都会想到归并排序... 一.二路归并 已知两个有序数组,将其归并为一个有序数组 很显然,将首元素比较,小的扔进目的数组,最后把剩下的扔进去.. 1 int a[n],b[m],tmp[n+m]; 2 int i=1,j=1,k=1; 3 while(i<=n&&

[USACO17FEB] Why Did the Cow Cross the Road I P (树状数组求逆序对 易错题)

题目大意:给你两个序列,可以序列进行若干次旋转操作(两个都可以转),对两个序列相同权值的地方连边,求最少的交点数 记录某个值在第一个序列的位置,再记录第二个序列中某个值 在第一个序列出现的位置 ,求逆序对数量即可 本以为是一道逆序对水题,结果被卡了20分.看了题解才恍然大悟,实际上,序列可以旋转 ≠ 序列成环,由于逆序对的特殊性(并不适用于环),故不能把一个序列单独旋转看成它们的相对移动,正着旋转一个序列≠反着旋转另一个序列(更详细证明可以看洛谷) 所以我们要对两个序列再反着进行一次同样的操作

Codevs 1688 求逆序对(权值线段树)

1688 求逆序对 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目 数据范围:N<=105.Ai<=105.时间限制为1s. 输入描述 Input Description 第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数. 输出描述 Output Description 所

【CodeVS1688】求逆序对

Description 给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目 Input 第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数. Output 所有逆序对总数. Sample Input 4 3 2 3 2 Sample Output 3 HINT 数据范围:N<=105.Ai<=105.时间限制为1s. 题解 归并排序,合并的时候,如果a[i]>a[j],那么a[i~mid]>a[j],

主席树初探 &amp; bzoj 3295: [Cqoi2011] 动态逆序对 题解

[原题] 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 778  Solved: 263 [Submit][Status] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元