zoukankan      html  css  js  c++  java
  • [HAOI2009] 逆序对数列

    观察数据范围我们发现可以用DP来做这个题qwq,因为它每一位往上填的时候,无论怎么填,总可以从前面的状态转移过来。

    而且题目保证了是从1-n的自然数,所以不存在相同数字的情况。

    我们设计状态(dp[i][j])为长度为i的序列(也就是前(i)个自然数)排成的序列中逆序对数量为(j)的答案个数。

    之后的转移就是往原先的序列中塞下一个数,填的位置不同自然增加的逆序对数量不一样,但是显然增加的数量只能在(0)({i-1})中。

    首先我们可以考虑暴力的(n^3)做法。

    转移方程:

    [dp[i][j]=sum_{k=0}^{max(j-i+1,0)}dp[i-1][k] ]

    试了试竟然有90分???

    但是显然1000的数据不是让我们用(n^3)闹着玩的。所以我们要试图将它优化到(n^2)。这个优化很容易,打个表我们稍加思考就可以发现,每次加的数有重复,而且是以前缀和的形式出现的。所以我们直接记录前缀和做优化就可以省略掉k的遍历了。

    (sum[i][j])来记录前i个数前j个逆序的答案个数。。。。就行了吧qwq

    代码如下。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define mod 10000
    using namespace std;
    int n,k;
    int dp[1010][1010],sum[1010][1010];
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=0;i<=n;i++) dp[i][0]=1,sum[i][0]=1;
      	sum[0][0]=0;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=k;j++)
    		{
    			dp[i][j]=(dp[i][j]+sum[i-1][j])%mod;
    			if(j-i>=0) dp[i][j]=(dp[i][j]+mod-sum[i-1][j-i])%mod;
    			sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
    		}
    	}
    	printf("%d
    ",dp[n][k]);
    	return 0;
    } 
    
  • 相关阅读:
    获取父类参数类型工具类
    date工具类
    Ascii工具类
    AES加解密工具类
    请求ip获取工具类
    对象和map互相转换工具类
    HTTP中get、post请求工具类
    时间日期各种工具类
    算法练习题——两数相除
    ETag
  • 原文地址:https://www.cnblogs.com/fengxunling/p/9834917.html
Copyright © 2011-2022 走看看