解题报告: CF1288C
题目链接:CF1288C Two Arrays
\(dp\)被暴切了,真开心<-睿智\(xxs\)
本题有\(\mathcal O(n+m),\mathcal O(nm),\mathcal O(n^2m)\)的做法,当然我一眼只能切出\(\mathcal O(nm)\)的做法,不过\(\mathcal O(n+m)\)应该也是可做的。
看到题目很多限制,不禁慌乱,不过自己写一写很快发现满足:
\[a_1\leqslant a_2\leqslant ......\leqslant a_n\leqslant b_n\leqslant b_{n-1}\leqslant b_1
\]
然后用\(dp\)来动态更新组合数即可,大概是这样的:
我们设\(dp[i][j]\)为第\(i\)小位置上结尾数(及最大数)为\(j\)的组合种数,那么:
\[dp[i][j]=\sum\limits_{k=1}^jdp[i-1][k]
\]
这样就是\(\mathcal O(n^2m)\)的做法,不过容易发现\(dp[i][j]=dp[i][j-1]+dp[i-1][j]\)(我们这里把\(dp[i][0]\)初始化为\(0\)),这样就能做到\(\mathcal O(nm)\)了。
\(Code\);
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MOD 1000000007
int n,m;
int dp[25][1005];
int ans=0;
int main()
{
#define read(x) scanf("%d",&x)
read(n),read(m);
m*=2;
for(int i=1;i<=n;i++) dp[1][i]=1;
for(int i=2;i<=m;i++)
{
for(int j=1;j<=n;j++) dp[i][j]=(dp[i][j-1]+dp[i-1][j])%MOD;
}
for(int i=1;i<=n;i++) ans=(ans+dp[m][i])%MOD;
printf("%d\n",ans%MOD);
return 0;
}