题目链接:http://codeforces.com/contest/1288/problem/C
题意:给定n和m,构造数组a和b,满足,ai非递减,bi非递增;ai<=bi,1<=i<=m,1<=ai,bi<=n。
求有多少数组对(a,b)满足题意,其中1<=n<=1000,1<=m<=10。
朴素解法,一个递增,一个递减,我们预处理dp[k][i]表示有k个数,且第k位数为i的非递减的序列数。则答案累加上所有的
d
p
[
m
]
[
i
]
∗
d
p
[
m
]
[
j
]
dp[m][i]*dp[m][j]
dp[m][i]∗dp[m][j],其中1<=j<=i<=n。
时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1010;
const int mod=1e9+7;
int n,m;
ll dp[22][maxn];
void Add(ll &x,int y){
x+=y;
if(x>=mod) x-=mod;
}
int main(){
while(~scanf("%d%d",&n,&m)){
//m<<=1;
for(int i=1;i<=n;i++) dp[1][i]=1;
for(int k=2;k<=m;k++){
for(int i=1;i<=n;i++){
// for(int j=1;j<=i;j++){
// Add(dp[k][i],dp[k-1][j]);
// }
dp[k][i]=(dp[k-1][i]+dp[k][i-1])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++)
Add(ans,dp[m][i]*dp[m][n-j+1]%mod);
}
printf("%I64d\n",ans);
}
return 0;
}
有趣的转化:https://blog.csdn.net/Nothing_but_Fight/article/details/103983854
(以下论述摘自以上博客)
1、序列a非递减,即
a
m
a_m
am是a中最大的数
2、序列b非递增,即
b
m
b_m
bm是b中最小的数
3、由
a
i
≤
b
i
a_i≤b_i
ai≤bi可得
a
m
≤
b
m
a_m≤b_m
am≤bm
有上述三点可以推出:
先顺序遍历序列a,再逆序遍历序列b,可以得到一个长度为2m的非递减序列c。(即将序列a和b的尾部相连)
至此,题目转换为求满足以下条件的序列c的个数:
1、长度为2m
2、ci的取值范围为[1,n]
3、序列c非递减
d
p
dp
dp解决此问题:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示满足以下条件的序列个数:
1、长度为i
2、第一个数为j
3、序列非递减
该方法时间复杂度为
O
(
n
m
)
O(nm)
O(nm)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1010;
const int mod=1e9+7;
int n,m;
ll dp[22][maxn];
void Add(ll &x,int y){
x+=y;
if(x>=mod) x-=mod;
}
int main(){
while(~scanf("%d%d",&n,&m)){
m<<=1;
for(int i=1;i<=n;i++) dp[1][i]=1;
for(int k=2;k<=m;k++){
for(int i=1;i<=n;i++){
dp[k][i]=(dp[k-1][i]+dp[k][i-1])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++){
Add(ans,dp[m][i]);
}
printf("%I64d\n",ans);
}
return 0;
}