C. Array-动态规划+滚动数组

Posted booiris

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C. Array-动态规划+滚动数组相关的知识,希望对你有一定的参考价值。

# C. Array

题目:

JSKZC is the captain of the lala team.

There are N girls in the lala team. And their height is [1,N] and distinct. So it means there are no two girls with the same height.

JSZKS has to arrange them as an array from left to right and let h[i] be the height of the ith girl counting from left. After that, he can calculate the sum of the inversion pairs. A inversion pair counts if h[i]>h[j] with i<j.

Now JSZKC wants to know how many different arranging plans with the sum of inversion pairs equalling K. Two plans are considered different if and only if there exists an i with h[i] different in these two plans.

As the answer may be very large, you should output the answer mod 1000000007.

Input
The input file contains several test cases, each of them as described below.

The first line of the input contains two integers N and K(1≤N≤5000,0≤K≤5000), giving the number of girls and pairs that JSZKC asked.
There are no more than 5000 test cases.

Output
An integer in one line for each test case, which is the number of the plans mod 1000000007.

思路:

题意是给出n个数,求使这n个数有k个逆序数对的方案有多少种。
递推公式:用dp(n,k)表示1~n排列中逆序数为k者的个数,则有:
\[dp(n,k+1)=dp(n,k)+dp(n-1,k+1)-dp(n-1,k+1-n)\]
下面分析递推公式
首先对于n-1个数形成的数列,当你要加入第n个数时,将它放在这个数列的末尾,显然不会产生新的逆序数对,当你把它放入数列的倒数第一个数前面时,会产生一个逆序数对,依次往下推,当你把它放在数列的首位,会产生n-1个逆序数对,所以当你放入第n个数时,会产生0~n-1个逆序数对。
这样就得到了初步的递推公式:
\[dp(n,k)= \sum_{x=0}^{k}dp(n-1,x)\]
一个一个求和显然太过复杂,再加一个公式:
\[dp(n,k+1)= \sum_{x=0}^{k+1}dp(n-1,x)\]
作差得到:

\[dp(n,k+1)= dp(n,k)+dp(n-1,k+1)\]
那么总的公式中“-dp(n-1,k+1-n)”是怎么出来的呢?
因为当k>n时,有一些数列已经无法通过加一个数来达到那么多的逆序数对了,毕竟加入一个数就只能增加n-1个逆序数对,所以我们要判断一下减去这些数列就行了~
对于这个题目还有一个问题,就是空间不够,要使用滚动数组,每次key=n&1代表着第n个数,!key代表第n-1个数就行了。
还有一个坑点,对于每个询问不能一次一次求,一定T,先保存所有询问,再在滚动过程中保存答案最后输出即可。

代码:

#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<stack>
#define INF 0x3f3f3f3f
using namespace std;
const int mod = 1000000007;
int dp[2][5005];
int ans[5005];
struct node
{
    int n, k;
    int index;
}q[5005];
int cnt;
bool cmp(const node &a, const node &b)
{
    return a.n < b.n;
}
int main()
{
    while (~scanf("%d%d", &q[cnt].n, &q[cnt].k))
    {
        q[cnt].index = cnt;
        cnt++;
    }
    sort(q, q + cnt, cmp);
    int now = 0;
    dp[0][0] = 1;
    for (int i = 1; i <= 5000; i++)
    {
        int key = i & 1;
        dp[key][0]=1;
        for (int j = 0; j < 5000; j++)
        {
            dp[key][j + 1] = (dp[key][j] + dp[!key][j + 1])%mod;
            if (j+1 >= i)
            {
                dp[key][j + 1] = (dp[key][j + 1] - dp[!key][j - i+1] + mod) % mod;
            }
        }
        while (now < cnt&&q[now].n == i)
        {
            ans[q[now].index] = dp[key][q[now].k];
            now++;
        }
    }
    for (int i = 0; i < cnt; i++)
    {
        printf("%d\n", ans[i]);
    }
}

以上是关于C. Array-动态规划+滚动数组的主要内容,如果未能解决你的问题,请参考以下文章

动态规划 解决二维最大子序和问题---滚动数组

动态规划 解决二维最大子序和问题---滚动数组

计算子数组和最大(动态规划)

动态规划和滚动数组的使用

力扣1567. 乘积为正数的最长子数组长度 动态规划+滚动数组

LeetCode刷题笔记-动态规划-day6