标签:span event 不同的 roman open 总数 输出 strong com
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000) 第2 - T + 1行:每行2个数n,k。中间用空格分隔。(2 <= n <= 1000, 0 <= k <= 20000)
共T行,对应逆序排列的数量 Mod (10^9 + 7)
1 4 3
6
dp+离线处理
我们很容易想到状态
dp[i][j] 代表在i个数的全排列中有j 的逆序数的方案数
下面我们来考虑这个状态的转移
显然将 i 插入 i-1 的排列中 不同的位置会产生不同的方案数
可能不产生逆序数 可能产生 1个 或 2个 或3个.....但最多能产生 i-1 个逆序数
于是 f[i][j]=f[i-1][j]+f[i-1][j-1]+f[i-1][j-2]+f[i-1][j-3]+f[i-1][j-4].........+f[i-1][j-(i-1)];
只有一个方程我们看不出怎么转移
我们 再找另一个方程 f[i][j-1];
f[i][j-1]=f[i-1][j-1]+f[i-1][j-1-1]+f[i-1][j-1-2]+f[i-1][j-1-2]...............f[i-1][j-1-(i-1)];
显然两个方程右边是有许多相同项的
我们用上式减去下式
得到 f[i][j]-f[i][j-1]=f[i-1][j]-f[i-1][j-1-(i-1)];
化简得到 f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i];
于是就可以转移了
1 #include <cstdio> 2 #include <cctype> 3 4 const int mod=1000000007; 5 const int MAXN=20010; 6 7 int T,n,m; 8 9 int dp[1010][MAXN]; 10 11 inline void read(int&x) { 12 int f=1;register char c=getchar(); 13 for(x=0;!isdigit(c);c==‘-‘&&(f=-1),c=getchar()); 14 for(;isdigit(c);x=x*10+c-48,c=getchar()); 15 x=x*f; 16 } 17 18 int hh() { 19 read(T); 20 for(int i=1;i<=1000;++i) dp[i][0]=1; 21 for(int i=2;i<=1000;++i) 22 for(int j=1;j<=20000&&j<=i*(i-1)/2;++j) { 23 dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod; 24 if(j-i>=0) dp[i][j]=((dp[i][j]-dp[i-1][j-i])%mod+mod)%mod; 25 } 26 while(T--) { 27 read(n);read(m); 28 printf("%d\n",dp[n][m]); 29 } 30 return 0; 31 } 32 33 int sb=hh(); 34 int main(int argc,char**argv) {;}
标签:span event 不同的 roman open 总数 输出 strong com
原文地址:http://www.cnblogs.com/whistle13326/p/7512237.html