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]
这两个求的内容是离奇相等的,求证。。。
题解
注意到数列中最大的数放下去以后,它所能产生的逆序对数是确定的。那么我们依次从大到小放,每次产生的逆序对数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; }
相关文章推荐
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- 简单的四则运算
- 数的奇偶性
- LFC1.0.0 版本发布
- Android px、dp、sp之间相互转换
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- 矩阵的乘法操作
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂