• 刷题记录(NC16708 过河卒,NC16619 传球游戏,NC16810 [NOIP1999]拦截导弹)


    NC16708 过河卒

    题目链接

    关键点:

    1、因为棋子可以往右边或者下边走一步,因此每一个点都可以从他的上边或者左边走过来:

    状态转移方程:dp[i][j] = dp[i][j-1]+dp[i-1][j];,表示第i行第j列总共的步数

    2、关于马能走到的点和本身的dp要置为0,说明该点的走法为0

    3、还有一点很关键:关于边界第0行和第0列,如果在没有马的情况下,除了起点(0,0)dp为0,其他都初始化为1,只能从起点走过来一条路,但是如果有马挡在0行(列)的第j列(行)那么包括该点和之后的该行(列)的dp都应该为0

    完整代码:

    1. # include
    2. using namespace std;
    3. int n, m, x, y;
    4. long long dp[30][30];
    5. int X[10] = {-1, -2, -2, -1, 1, 2, 2, 1};
    6. int Y[10] = {-2, -1, 1, 2, 2, 1, -1, -2};
    7. int ma[30][30];
    8. int main()
    9. {
    10. cin>>n>>m>>x>>y;
    11. ma[x][y] = 1;
    12. for (int i=0; i<8; i++)
    13. {
    14. int x1 = x+X[i];
    15. int y1 = y+Y[i];
    16. if (x1<0||y1<0||x1>n||y1>m)
    17. continue;
    18. ma[x1][y1] = 1;
    19. // cout<
    20. }
    21. for (int i=1; i<=n; i++)
    22. {
    23. if (ma[i][0])
    24. break;
    25. dp[i][0] = 1;
    26. }
    27. // cout<
    28. for (int i=1; i<=m; i++)
    29. {
    30. if (ma[0][i])
    31. break;
    32. dp[0][i] = 1;
    33. // cout<
    34. }
    35. for (int i=1; i<=n; i++)
    36. {
    37. for (int j=1; j<=m; j++)
    38. {
    39. if (ma[i][j])
    40. dp[i][j] = 0;
    41. else
    42. dp[i][j] = dp[i-1][j] + dp[i][j-1];
    43. // cout<
    44. // cout<
    45. // cout<
    46. }
    47. }
    48. cout<
    49. return 0;
    50. }

    NC16619 传球游戏

    题目链接

    关键点:

    1、首先分析,对于第i次球传到j号手里,那么只能从i-1次的j左右传过来,因此状态转移方程:

    dp[i][j] = dp[i-1][j-1]+dp[i-1][j+1],表示第i次球传到j号手里的可能步数

    2、初始化,题目要求从1号小蛮开始,因此dp[0][1] = 1;

    3、因为是围成一个圈,因此1号是传给2和n号,n号是传给1和n-1号

    因此当j-1==0,令其为n

    当j+1==n+1,令其为1

    完整代码:

    1. # include
    2. using namespace std;
    3. int dp[40][40];//第i次传球,球在j手里
    4. int n, m;
    5. int main()
    6. {
    7. cin>>n>>m;
    8. dp[0][1] = 1;
    9. for (int i=1; i<=m; i++)
    10. {
    11. for (int j=1; j<=n; j++)
    12. {
    13. int j1 = j-1;
    14. int j2 = j+1;
    15. if (j1 == 0)
    16. j1 = n;
    17. if (j2==n+1)
    18. j2 = 1;
    19. dp[i][j] = dp[i-1][j1]+dp[i-1][j2];
    20. }
    21. }
    22. cout<1]<
    23. return 0;
    24. }

    NC16810 [NOIP1999]拦截导弹

    题目链接

    关键点:

    1、首先是明确题目要求求的是最长下降子序列,和最长上升子序列

    2、一般的dp求最长上升(下降)子序列复杂度为n^2,很明显会超时

    3、我们采用贪心+二分,比如求最长上升子序列,我们只要保证该数列的最后一个数尽可能的小,这样给后面的数字留的空间就大了,我们用一个low数组,先初始化为最大值,遍历原数组,对于每一个i,在low数组里找大于等于i的数的位置(lower_bound),放上去,不断更新子序列。然后倒着遍历low数组,哪个位置有数就该位就为答案

    4、同样的对于最长下降子序列,我们将原数组倒过来,然后用upper_bound即可

    1. # include
    2. using namespace std;
    3. const int inf = 30000+10;
    4. int h[100000+10];
    5. int res[100000+10];
    6. int low[100000+10];
    7. int ans1, ans2;
    8. int main()
    9. {
    10. int x, n=0;
    11. while (cin>>x)
    12. {
    13. h[++n] = x;
    14. }
    15. for (int i=1; i<=n; i++)
    16. {
    17. low[i] = inf;
    18. }
    19. for (int i=1; i<=n; i++)
    20. {
    21. int dex = lower_bound(low+1, low+1+n, h[i])-low;
    22. // cout<
    23. low[dex] = h[i];
    24. }
    25. for (int i=n; i>=1; i--)
    26. {
    27. if (low[i]!=inf)
    28. {
    29. ans2 = i;
    30. break;
    31. }
    32. }
    33. for (int i=n; i>=1; i--)
    34. res[i] = h[n-i+1];
    35. for (int i=1; i<=n; i++)
    36. {
    37. low[i] = inf;
    38. }
    39. for (int i=1; i<=n; i++)
    40. {
    41. int dex = upper_bound(low+1, low+1+n, res[i])-low;
    42. // cout<
    43. low[dex] = res[i];
    44. }
    45. for (int i=n; i>=1; i--)
    46. {
    47. if (low[i]!=inf)
    48. {
    49. ans1 = i;
    50. break;
    51. }
    52. }
    53. cout<
    54. return 0;
    55. }

  • 相关阅读:
    概率论与数理统计
    基于微信小程序的火锅店点餐订餐系统设计与实现(源码+lw+部署文档+讲解等)
    docker基础篇:安装tomcat
    【560. 和为 K 的子数组】
    ros之乌龟做圆周运动and订阅乌龟的位姿信息
    行行AI人工智能大会 | LTD荣获“AI强应用创新TOP50代表企业”
    Linux开发——Makefile 基础(九)
    Vue:生命周期(从出生到销毁)
    Python 网络请求工具库
    关于 Python 的经典入门书籍有哪些?
  • 原文地址:https://blog.csdn.net/m0_60531106/article/details/126594038