您的位置:首页 > 其它

51NOD 1020 逆序排列

2015-12-29 12:41 381 查看
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1020

题解

注意到数列中最大的数放下去以后,它所能产生的逆序对数是确定的。

那么我们依次从大到小放,每次产生的逆序对数x,有0≤x≤(n−已经下放的个数)

然后我们令f[i][j]表示已经下放了i个数,逆序对数为j,的方案数。

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

那么有f[i][j]=∑0≤k≤min(j,n−i)f[i−1][j−k],边界为f[0][0]=1

那么接下来我们可以通过对右边的式子部分和优化,复杂度是O(nk)。

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

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

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

f[n−i][j]=∑0≤k≤min(j,i)f[(n−i)−1][j−k]=∑0≤k≤if[n−(i+1)][j−k]

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

f′[i][j]=∑0≤k≤if′[i+1][j−k]f′[n][0]=1

所以,这就是一个比较无言的误区。

并不知道这个怎么转换成另一个方程式

如果你一开始设的是剩下还有i个数没放,

那么可以直接想到f[i][j]=∑0≤k<if[i−1][j−k]f[0][0]=1

呵呵。。。。

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

f[i][j]=====∑0≤k<if[i−1][j−k]∑1≤k<i+1f[i−1][j−k]+f[i−1][j]−f[i−1][j−i]∑0≤k<if[i−1][j−(k+1)]+f[i−1][j]−f[i−1][j−i]∑0≤k<if[i−1][(j−1)−k]+f[i−1][j]−f[i−1][j−i]f[i][j−1]+f[i−1][j]−f[i−1][j−i]

存疑的问题是:

f[i][j]=∑0≤k≤if[i+1][j−k]f[n][0]=1,求f[0][K]

f[i][j]=∑0≤k<if[i−1][j−k]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
[k].print();
}

int main() {
pre();

int kase; scanf("%d", &kase);
while (kase --) solve();

//  for(;;);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 51NOD DP