当前位置:   article > 正文

cf场+线性dp

cf场+线性dp

Problem - B - Codeforces

思路:

这其实是一道数学题(最开始一直在枚举,服啦)

我们的目的是求最大利润

当a>=b是时直接令k=0,利润=n*a即可

当a<b时存在两种情况:

1.b-a>=n即所有b-i+1的情况都>a,这个时候我们把b-i+1看成一个等差数列求和即可

2.n>b-a>0这种情况我们还需要考虑到使用到的a,在此之前我们按照等差数列出售了(b-a)个,那么剩下n-(b-a)个我们则需要按照a来出售

还可以参考我觉得挺好的一篇题解:

题解:CF1978B New Bakery-CSDN博客

AC代码:

  1. void solve()
  2. {
  3. ll n, a, b, ans;
  4. cin >> n >> a >> b;
  5. if (a >= b)
  6. {
  7. cout << a * n << endl;
  8. return;
  9. }
  10. else
  11. {
  12. ll k = min(n, b - a);
  13. cout << (b + b - k + 1) * k / 2 + a * (n - k) << endl;
  14. return;
  15. }
  16. return;
  17. }

Problem - B - Codeforces

思路:

采用双指针,一个指向a的头部,一个指向b的头部,两者开始进行匹配,若相同则b往下走一位,否则就终止

AC代码:

  1. void solve()
  2. {
  3. ll n, m;
  4. cin >> n >> m;
  5. cin >> a >> b;
  6. a = " " + a, b = " " + b;//相当于char a[],然后cin>>a+1
  7. ll sum = 0, j = 1;
  8. for (int i = 1; i <= n; i++)
  9. {
  10. for (; j <= m; j++)
  11. {
  12. if (a[i] == b[j])
  13. {
  14. sum++;
  15. j++;
  16. break;
  17. }
  18. }
  19. if (j > m)
  20. break;
  21. }
  22. cout << sum << endl;
  23. return;
  24. }

还有一篇动态规划的题解我感觉也不错

Prefiquence(双指针,动态规划)-CSDN博客

代码奉上:

  1. void solve()
  2. {
  3. ll n, m;
  4. cin >> n >> m;
  5. cin >> a >> b;
  6. a = " " + a, b = " " + b;
  7. dp[1] = (a[1] == b[1] ? 1 : 0);
  8. for (int i = 2; i <= m; i++)
  9. {
  10. if (dp[i - 1] < n && a[dp[i - 1] + 1] == b[i])
  11. {
  12. dp[i] = dp[i - 1] + 1;
  13. }
  14. else
  15. {
  16. dp[i] = dp[i - 1];
  17. }
  18. }
  19. cout << dp[m] << endl;
  20. return;
  21. }

Problem - C - Codeforces

思路:

令a[1]=x[1]+1后我们可以让a[i+1]=a[i]+x[i],但是这样的话数可能会比较小,所以我们可以累加a[i],因为是mod所以只要不大于x[i+1]可以一直加下去

代码:

  1. void solve()
  2. {
  3. int n;
  4. cin >> n;
  5. for (int i = 1; i < n; i++)
  6. cin >> x[i];
  7. a[1] = x[1] + 1;
  8. for (int i = 1; i < n; i++)
  9. {
  10. a[i + 1] = a[i] + x[i];
  11. while (a[i + 1] <= x[i + 1])
  12. {
  13. a[i + 1] += a[i];
  14. }
  15. }
  16. for (int i = 1; i <= n; i++)
  17. {
  18. cout << a[i] << " ";
  19. }
  20. cout << endl;
  21. return;
  22. }

P1020 [NOIP1999 提高组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目的第一问其实就是让我们求最长不上升子序列,第二问就是求有多少段最长不上升序列

dp代码:

  1. void solve2()
  2. {
  3. int res = 0;
  4. for (int i = 0; i < n; i++)
  5. {
  6. dp[i] = 1;
  7. for (int j = 0; j < i; j++)
  8. {
  9. if (a[j] > a[i])
  10. {
  11. dp[i] = max(dp[i], dp[j] + 1);
  12. }
  13. }
  14. res = max(res, dp[i]);
  15. }
  16. cout << ans << endl;
  17. return;
  18. }

然后我们发现就只会有50分,因为这个代码的时间复杂度达到了n^2,和题目的要求时间复杂度差距非常大,我们改善一下

  1. void solve()
  2. {
  3. vector<int>c;
  4. int ans = 0;
  5. while (cin >> a[num])
  6. {
  7. dp[num] = 1;
  8. for (int i = 0; i < num; i++)
  9. {
  10. if (a[num] <= a[i])
  11. dp[num] = max(dp[num], dp[i] + 1);
  12. }
  13. ans = max(ans, dp[num]);
  14. int flag = 0;
  15. for (int i = 0; i < c.size(); i++)
  16. {
  17. if (c[i] >= a[num])
  18. {
  19. flag = 1;
  20. c[i] = a[num];
  21. break;
  22. }
  23. }
  24. if (flag == 0)c.push_back(a[num]);
  25. num++;
  26. }
  27. cout << ans << endl;
  28. cout << c.size() << endl;
  29. return;
  30. }

我们用一个 vector来存放最长不上升子序列,当前数若比vector的所有数小就进行覆盖,若大则加进vector,这样子操作的话vector的长度就会是我们所需子序列的个数,提交之后发现还是只有100,只能说这道题对时间复杂度卡的太死了,继续优化,这个时候可以根据Dilworth 定理进行推断:

狄尔沃斯定理亦称偏序集分解定理,该定理断言:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目。

得到如下代码:

  1. void solve1()
  2. {
  3. int ta = 0, x, tb = 0;
  4. while (cin >> x)
  5. {
  6. int s = 0;
  7. for (int i = 0; i < ta; i++)
  8. {
  9. if (a[i] < x)
  10. {
  11. a[i] = x;
  12. s = 1;
  13. break;
  14. }
  15. }
  16. if (s == 0)a[ta++] = x;
  17. s = 0;
  18. for (int i = 0; i < tb; i++)
  19. {
  20. if (b[i] >= x)
  21. {
  22. b[i] = x;
  23. s = 1;
  24. break;
  25. }
  26. }
  27. if (s == 0)b[tb++] = x;
  28. }
  29. cout << ta << endl << tb << endl;
  30. return;
  31. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/895194
推荐阅读
相关标签
  

闽ICP备14008679号