[NOIP模拟][dp][codevs]p1401逆序对统计
2016-11-03 16:21
405 查看
题目描述 Description
我们说(i,j)是a1,a2,…,an的一个逆序对当且仅当i<j且ai>aj。例如2,4,1,3,5的逆序对有3个,分别为(1,3),(2,3),(2,4)。现在已知N和K,求1..N的所有特定排列,这些排列的逆序对的数量恰好为K。输出这些特定排列的数量。
例如N=5,K=3的时候,满足条件的排列有15个,它们是:
1,2,5,4,3 1,3,4,5,2 1,3,5,2,4 1,4,2,5,3 1,4,3,2,5
1,5,2,3,4 2,1,4,5,3 2,1,5,3,4 2,3,1,5,4 2,3,4,1,5
2,4,1,3,5 3,1,2,5,4 3,1,4,2,5 3,2,1,4,5 4,1,2,3,5
输入描述 Input Description
输入第一行有两个整数N和K。其中(N<=100,K<=N*(N-1)/2)
输出描述 Output Description
将1..N的逆序对数量为K的特定排列的数量输出,为了避免高精度计算,请将结果mod10000后再输出
样例输入 Sample Input
【样例输入1】
5 3
【样例输入2】
10 7
【样例输入3】
10 10
样例输出 Sample Output
【样例输出1】
15
【样例输出2】
4489
【样例输出3】
1670
方程很容易得出:f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
但是若果这样是O(n^3)
可以优化为O(n^2)
f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
f[i][j-1]=f[i-1][j-i]+f[i-1][j-i+1]+f[i-][j-i+2]+……+f[i-1][j-1]
这两个式子有许多重复项
所以可以合并为f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i]
代码:
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define INF 0x3f3f3f3f
#define clock CLOCKS_PER_SEC
#define cle(x) memset(x,0,sizeof(x))
#define maxcle(x) memset(x,127,sizeof(x))
#define mincle(x) memset(x,-1,sizeof(x))
#define cop(a,x) memcpy(x,a,sizeof(a))
#define FROP "codvs"
#define C(a,b) next_permutation(a,b)
#define LL long long
using namespace std;
const int N=105,mod=1e4;
int n,k,f[N*N/2]
;
int main()
{
freopen(FROP".in","r",stdin);
freopen(FROP".out","w",stdout);
scanf("%d%d",&n,&k);
for(int i = 0 ; i <= n; i++)
f[0][i]=1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= k; j++)
{
f[j][i]=(f[j][i-1]+f[j-1][i])%mod;
if(j>=i)f[j][i]=(f[j][i]-f[j-i][i-1]+mod)%mod;//!!!!!!!1减后防止为负数,,而且j>=i!!!!!!
}
printf("%d",f[k]
);
return 0;
}
还有两点很重要
1.j>=i,,数组下标运算时,不能为负数。。。!!!!!!!!注意判断,,,这个递推式子。。
2.当要模一个数的时候,,,特别当有减的时候,,一定要加上这个数在减去在模,防止模后又减去未负数!!!!!!!!!
if(j>=i)f[j][i]=(f[j][i]-f[j-i][i-1]+mod)%mod;///////////!!!!!!!!!!!!!!
我们说(i,j)是a1,a2,…,an的一个逆序对当且仅当i<j且ai>aj。例如2,4,1,3,5的逆序对有3个,分别为(1,3),(2,3),(2,4)。现在已知N和K,求1..N的所有特定排列,这些排列的逆序对的数量恰好为K。输出这些特定排列的数量。
例如N=5,K=3的时候,满足条件的排列有15个,它们是:
1,2,5,4,3 1,3,4,5,2 1,3,5,2,4 1,4,2,5,3 1,4,3,2,5
1,5,2,3,4 2,1,4,5,3 2,1,5,3,4 2,3,1,5,4 2,3,4,1,5
2,4,1,3,5 3,1,2,5,4 3,1,4,2,5 3,2,1,4,5 4,1,2,3,5
输入描述 Input Description
输入第一行有两个整数N和K。其中(N<=100,K<=N*(N-1)/2)
输出描述 Output Description
将1..N的逆序对数量为K的特定排列的数量输出,为了避免高精度计算,请将结果mod10000后再输出
样例输入 Sample Input
【样例输入1】
5 3
【样例输入2】
10 7
【样例输入3】
10 10
样例输出 Sample Output
【样例输出1】
15
【样例输出2】
4489
【样例输出3】
1670
方程很容易得出:f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
但是若果这样是O(n^3)
可以优化为O(n^2)
f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
f[i][j-1]=f[i-1][j-i]+f[i-1][j-i+1]+f[i-][j-i+2]+……+f[i-1][j-1]
这两个式子有许多重复项
所以可以合并为f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i]
代码:
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define INF 0x3f3f3f3f
#define clock CLOCKS_PER_SEC
#define cle(x) memset(x,0,sizeof(x))
#define maxcle(x) memset(x,127,sizeof(x))
#define mincle(x) memset(x,-1,sizeof(x))
#define cop(a,x) memcpy(x,a,sizeof(a))
#define FROP "codvs"
#define C(a,b) next_permutation(a,b)
#define LL long long
using namespace std;
const int N=105,mod=1e4;
int n,k,f[N*N/2]
;
int main()
{
freopen(FROP".in","r",stdin);
freopen(FROP".out","w",stdout);
scanf("%d%d",&n,&k);
for(int i = 0 ; i <= n; i++)
f[0][i]=1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= k; j++)
{
f[j][i]=(f[j][i-1]+f[j-1][i])%mod;
if(j>=i)f[j][i]=(f[j][i]-f[j-i][i-1]+mod)%mod;//!!!!!!!1减后防止为负数,,而且j>=i!!!!!!
}
printf("%d",f[k]
);
return 0;
}
还有两点很重要
1.j>=i,,数组下标运算时,不能为负数。。。!!!!!!!!注意判断,,,这个递推式子。。
2.当要模一个数的时候,,,特别当有减的时候,,一定要加上这个数在减去在模,防止模后又减去未负数!!!!!!!!!
if(j>=i)f[j][i]=(f[j][i]-f[j-i][i-1]+mod)%mod;///////////!!!!!!!!!!!!!!
相关文章推荐
- codevs 1164 || NOIP 2007 统计数字 模拟 解题报告
- 【codevs1039】01年noip TG--数的划分满分dp+愚蠢深搜+pas的奇怪做法
- Codevs_1040_[NOIP2001]_统计单词个数_(划分型动态规划)
- 【codevs1040】【01NOIPTG】统计单词个数,字符串的划分DP
- Codevs 1315 摆花 ——2012年NOIP全国联赛普及组 dp递推
- CodeVS 1090 [NOIP 2003] 区间DP 解题报告
- codevs1040统计单词个数(区间+划分型dp)
- [CODEVS1090][NOIP2013]加分二叉树(树形dp)
- 【贪心】CODE[VS] 1063 NOIP2004普及组-合并果子 (刷题记录(模拟+优先队列))
- CodeVS 1107 等价表达式【NOIP2005】【模拟
- codevs1040 统计单词个数(区间dp+划分dp)
- [NOIP2005][CODEVS1106]篝火晚会(模拟+数学相关)
- 【NOIP2008】 CODE[VS] 1169 传纸条(棋盘型DP)
- POJ1651 Codevs1017 乘积最大 ---2000年NOIP全国联赛提高组 dp
- codevs 1126 数字统计 2010年NOIP全国联赛普及组 x
- 【vijos P1914】【codevs 3904】[NOIP2014 普及组T4]子矩阵(dfs+状压dp)
- (昨天的)codevs 天梯 统计单词个数 dp
- 【NOIP2004】CODE[VS] 1058 合唱队形(序列型DP)
- 【NOIP】CODE[VS] 1044 拦截导弹 动态规划 序列型DP
- 划分型动态规划 之 CODE[VS] 1040 统计单词个数 2001年NOIP全国联赛提高组