这貌似是2015年校赛现场赛第四题,记得2017年校赛前面五题基本都是数学题,顶多用个快速幂,没考什么算法知识,所以博主最初就是把这道题当数学题来看的。
题目链接:
xdoj 1056 寻找BOSS
题目大意:
平面直角坐标系中一个n*n的正方形,以(0,0)为起点,(n,n)为终点,有两种移动方式-——横着移1个单位或者竖着移一个单位,但是横纵坐标都只能加不能减且纵坐标不能超过横坐标(比如移动到(0,1)是不合法的),问在这种情况下起点到终点有多少种方案数。
稍加分析可以发现这题其实很简单,有点像一道基础DP题——当然,事实上这道题比DP少了决策这个过程,较之也更简单,说是递推更确切。
1、状态转移方程(说是递推关系式更确切):f(i,j)=f(i-1,j)+f(i,j-1) (0<j <= i,j为0那一行在边界条件中处理),其中i代表横坐标,j代表纵坐标,f(i,j)代表到达(i,j)格点的方案数,显然,对于格点(i,j)来说,能到达它只有(i-1,j)和(i,j-1)这两个格点,那么如果到达这两个格点的方案数已知,到达该点的坐标自然就是两者之和。
2、边界条件:f(i,0)=1(其中i=1,2,...,1000,其余皆预置为0即可)。 特殊的其实只有纵坐标为0和副对角线上的点,因此考虑边界条件时需要判断如何取初值。首先,显然纵坐标为0的行的格点的方案数除了(0,0)皆需为1,因为只可能从同一行的前一个格点转移过来,而(0,0)任取不影响结果。其次,对于副对角线上的点来说,因为不可能从同行的前一个格点转移而来,因此实际上到达它们的方案数就等于它们同一列纵坐标比之小1的格点的方案数。因此,只需要把除纵坐标为0的行的其他格点初值全置为0即可。
3、复杂度分析:由于不知道出题人有没有通过多组数据来让人TLE,所以最好的办法显然是先通过递推关系把所有可能询问的点的方案数都求出并存下来,以后每次查询时直接用结果即可。所以计算规模(1000+1000*1000/2)<1e6,加上O(1)查询,怎么都不可能超时的。
AC代码如下:
PS:博主的代码中i是纵坐标,j是横坐标。
#include#include#include#includeusing namespace std;
#define N 1010
#define P 10007
int f[N][N];
void init(){
for(int i=1;i<=1000;i++){
f[0][i]=1;
}
for(int i=1;i<=1000;i++){
for(int j=1;j<=i;j++){
f[j][i]=(f[j-1][i]+f[j][i-1])%P;
}
}
}
int main(){
int n;
init();
while(~scanf("%d",&n)){
printf("%d\n",f[n][n]);
}
return 0;
}