DP——51nod1020 逆序排列

来源:互联网 发布:php头部编码 编辑:程序博客网 时间:2024/06/10 20:31

题面:51nod1020
虽然这是5级题的第一个题目,但是作为这种水平的DP的话……
真的好神啊!!!(我貌似从来没有做过这种推状态转移方程的。。。
首先状态就是f[i][j]表示前i个数的排列逆序数的个数
i1推到i的话我们可以考虑到i排在第ip个位置上,这样就可以产生p个逆序对
所以朴素的状态转移方程就是

f[i][j]=p=0i1f[i1][jp]

这样的时间复杂度是O(n2m),考虑优化
我们可以把f[i][j1]给拿来和f[i][j]比较
f[i][j1]=p=0i1f[i1][j1p]

我们把第一个减去第二个,惊奇地发现f[i][j]f[i1][j]=f[i1][j]f[i1][ji]
所以f[i][j]=f[i1][j]+f[i][j1]f[i1][ji]
这样时间复杂度就O(n2),可以过啦
很巧妙是不是?

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <iostream>#include <ctime>#include <map>#include <queue>#include <cstdlib>#include <string>#include <climits>#include <set>#include <vector>using namespace std;inline int read(){    int k=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}    return k*f;}const int MOD=1e9+7;int f[1010][20010];int main(){    for(int i=0;i<=1000;i++)f[i][0]=1;    for(int i=2;i<=1000;i++)        for(int j=1;j<=min(20000,i*(i-1)/2);j++){            f[i][j]=(f[i-1][j]+f[i][j-1])%MOD;            if(j-i>=0)f[i][j]=(f[i][j]-f[i-1][j-i]+MOD)%MOD;        }    int T=read();    while(T--){        int x=read(),y=read();        printf("%d\n",f[x][y]);    }    return 0;}
原创粉丝点击