zbrka

Description

考虑一个由N个整数构成的数列,其中1到N都在数列中出现了恰好一次。 
在这个数列中从左到右任取两个数,如果前者比后者大,那么这对数就是一个逆序对。 
而整个数列的逆序数就是其中所有逆序对的总数。 
例如,数列(1,4,3,2)的逆序数为3,因为存在三个逆序对:(4,3),(4,2)和(3,2)。 
写一个程序,计算有多少长度为N的这种数列,使它的逆序数恰为C。

Input

输入包含两个整数N(1≤N≤1000)和C(1≤C≤10000)。

Output

计算出所求的答案,将它mod 1,000,000,007后输出。

Sample Input

输入样例1:
10 1
输入样例2:
4 3
输入样例3:
9 13

Sample Output

输出样例1:
9
输出样例2:
6
输出样例3:
17957


【分析】

f[i][j]表示用数字1~i拼成j个逆序对的方案数。
注意到一件事情,用数字{1,2,..,n}等价于用数字{2,3,..,n+1}

所以我们枚举1的位置:
得到状态转移方程 f[i][j]=sigma(f[i-1][j-k]) 0<=k<=i-1

这个方程怎么来的呢,

我们用数字{1,2,..,i-1},由上面第二排的话,等价于用数字{2,3,..,i}来拼成j-k个逆序对。
这个时候还差k个逆序对,我们可以将数字1唯一地插入数字{2,3,...,i}组成的每个方案中,得到k个逆序对

(这样一定是可行的,因为1对后面不产生逆序对,而对前面,有多少个数,就产生多少个逆序对)

貌似问题完美解决了。。。
但是。。
时间复杂度O(N*N*C)
空间复杂度O(N*C)
:(

所以我们可以优化。。
展开方程:f[i][j]=f[i-1][j-i+1] + f[i-1][j-i+2] +...+ f[i-1][j-1] + f[i-1][j]
注意到: f[i][j-1]=f[i-1][j-i] + f[i-1][j-i+1] +..+ f[i-1][j-2] + f[i-1][j-1]
而f[i][j-1]比f[i][j]多了个f[i-1][j-i],少了个f[i-1][j]
所以我们构造:
    f[i][j]=f[i][j-1] + f[i-1][j] - f[i-1][j-i]

现在。。
时间复杂度O(N*C)
空间复杂度O(C)
:)

等等。。
为什么空间复杂度O(C)?!!  因为可以用滚动数组。。


【代码】

/* Ciocio's OI Template */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <deque>
#include <functional>
#include <vector>
#include <stack>
#include <list>
#include <bitset>

using namespace std;

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define sz(x) x.size()
#define ll long long
#define p_b push_back
#define m_p make_pair
#define pii pair<int,int>
#define pf printf
#define sf scanf
#define x first
#define y second
#define pp_b pop_back
#define pp_f pop_front
#define INF (~0U>>3)

#define MODER 1000000007
#define MAXC 10000

int N,C;
ll f[2][MAXC+10];

void _init(){
    cin>>N>>C;
}

void _solve(){
    //f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i];
    f[0][0]=1;
    f[1][0]=1;
    rep(i,1,N){
        int t=i&1;
        rep(j,1,C){
            f[t][j]=f[t][j-1]+f[t^1][j];
            f[t][j]%=MODER;
            if(j-i>=0)
                f[t][j]=(f[t][j]-f[t^1][j-i]+MODER)%MODER;
        }
    }
    cout<<f[N&1][C]<<endl;
}

int main(){
	_init();
	_solve();
	return 0;
}



展开阅读全文

没有更多推荐了,返回首页