51NOD 1020 逆序排列

来源:互联网 发布:mac上音频剪辑软件 编辑:程序博客网 时间:2024/04/28 22:42

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1020

题解

注意到数列中最大的数放下去以后,它所能产生的逆序对数是确定的。
那么我们依次从大到小放,每次产生的逆序对数x,有0x(n)
然后我们令f[i][j]表示已经下放了i个数,逆序对数为j,的方案数。


接下来是陷进了奇怪的地方。。

那么有f[i][j]=0kmin(j,ni)f[i1][jk],边界为f[0][0]=1
那么接下来我们可以通过对右边的式子部分和优化,复杂度是O(nk)

然而,这是多组数据,会跪。。。。

然而更糟糕的是,我们的求和项里存在n,没法一起算。。。。

这里有个处理的方法,就是i=ni带入原式,那么就有:(这一步只是替换求和指标,没有实质上变化)

f[ni][j]=0kmin(j,i)f[(ni)1][jk]=0kif[n(i+1)][jk]

其中,我们令f[][<0]=0,然后,令f[i][j]=f[ni][j](这一步定义一个新的数列,f复制一份给f
f[i][j]=0kif[i+1][jk]f[n][0]=1

所以,这就是一个比较无言的误区。
并不知道这个怎么转换成另一个方程式


如果你一开始设的是剩下还有i个数没放,
那么可以直接想到

f[i][j]=0k<if[i1][jk]f[0][0]=1

呵呵。。。。
接着,你可以用部分和优化,或者比较漂亮的做法是:

f[i][j]=====0k<if[i1][jk]1k<i+1f[i1][jk]+f[i1][j]f[i1][ji]0k<if[i1][j(k+1)]+f[i1][j]f[i1][ji]0k<if[i1][(j1)k]+f[i1][j]f[i1][ji]f[i][j1]+f[i1][j]f[i1][ji]

存疑的问题是:

f[i][j]=0kif[i+1][jk]f[n][0]=1,f[0][K]

f[i][j]=0k<if[i1][jk]f[0][0]=1,f[n][K]

这两个求的内容是离奇相等的,求证。。。

code

#include <algorithm>#include <bitset>#include <cassert>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#include <deque>#include <iostream>#include <map>#include <queue>#include <set>#include <string>#include <vector>using namespace std;typedef long long LL;const int mod = 1000000007;struct modn {    int n;    modn() { }    modn(LL x) { n = (x >= 0 ? x%mod : (x%mod+mod)%mod); }    modn& operator -() { n = mod-n; return *this; }    void print() const { printf("%d\n", n); }};bool operator ==(const modn& A, const modn& B) { return A.n == B.n; }bool operator !=(const modn& A, const modn& B) { return A.n != B.n; }modn operator +(const modn& A, const modn& B) { return A.n + B.n; }modn operator -(const modn& A, const modn& B) { return A.n - B.n; }modn operator *(const modn& A, const modn& B) { return (LL)A.n * B.n; }modn operator +=(modn& A, const modn& B) { return A = A + B; }modn operator -=(modn& A, const modn& B) { return A = A - B; }modn operator *=(modn& A, const modn& B) { return A = A * B; }const int maxn = 1010;const int maxk = 20010;modn f[maxn][maxk];void pre() {    f[0][0] = 1;    for (int i = 1; i < maxn; ++ i) {        modn s = 0;        for (int j = 0; j < maxk; ++ j)            f[i][j] = (j >= 1 ? f[i][j-1] : 0) + f[i-1][j] - (j >= i ? f[i-1][j-i] : 0);    }}int n, k;void solve() {    scanf("%d%d", &n, &k);    f[n][k].print();}int main() {    pre();    int kase; scanf("%d", &kase);    while (kase --) solve();//  for(;;);    return 0;}
0 0
原创粉丝点击