51NOD 1020 逆序排列(dp预处理)

  定义dp[i][j]为1~i的排列里逆序数为j的方案数。那么只需要求i阶段的dp值时,只需要考虑在i-1阶段的基础上把i放哪里就好了,如果i放在倒数第v个就会新产生v-1个逆序对。那么转移方程就是dp[i][j]=sum(dp[i-1][j-v])  0<=v<=min (j,i-1),如果单单这样的话复杂度是n*k*k,因为转移是由上一阶段一个连续区间的dp值转移来的,所以在算i阶段dp值时可以先处理出i-1阶段dp值的前缀和,这样转移就O(1)了

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define PI acos(-1)
#define eps 1e-8
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int> pii;
const int inf=2e9;
const int maxn=1e6+10;
const int mod=1e9+7;
int d[4][2]={1,0,-1,0,0,1,0,-1};
//int lowbit(int x){return x&-x;}
//void add(int x,int v){while(x<=n)bit[x]+=v,x+=lowbit(x);}
//int sum(int x){int ans=0;while(x>=1) ans+=bit[x],x-=lowbit(x);return ans;}
inline ll read() {
    ll s = 0,w = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
        s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
inline void write(ll x) {
    if(x < 0)
        putchar('-'), x = -x;
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

int dp[1005][(int)2e4+10],pre[(int)2e4+10];

int main(){
    dp[1][1]=0,dp[1][0]=1;
    pre[0]=1,pre[1]=1;
    for(int i=2;i<=1000;i++){
        for(int j=0;j<=min(20000,i*(i-1)/2);j++) {
            if (i - 1 >= j)
                dp[i][j] = pre[j];
            else
                dp[i][j] = (pre[j] - pre[j - i]+mod)%mod;
        }
        for(int j=0;j<=20000;j++){
            if(j==0)
                pre[j]=dp[i][j];
            else
                pre[j]=(pre[j-1]+dp[i][j])%mod;
        }
    }
    int t,n,k;
    t=read();
    while(t--){
        n=read();k=read();
        write(dp[n][k]);puts("");
    }
    return 0;
}





原文地址:https://www.cnblogs.com/eason9906/p/11754696.html