• D. Trees and Segments Codeforces Round 893 (Div. 2)


    Problem - D - Codeforces

    题目大意:给出一个长度为n的仅由0和1的字符串,最多可以进行k次操作,每次操作可以将一个位置上的数取反。令a等于最大连续0的数量,令b等于最大连续1的数量,求i分别属于1~n时,i*a+b的最大值。

    1<=n<=3000;0<=k<=n

    思路:因为每个a,对应的b都不同,所以对于一个确定的i,我们只要求出当a为1~n中某个合法的数时,对应的最大的b是多少,然后枚举a求最大值即可。

    我们令dp[i][j]表示修改j次,在[i,n]中最大有多少个1,首先大区间能从小区间转移,dp[i][j]=dp[i+1][j],然后求出在i~n内0的数量cnt,dp[i][cnt]=max(dp[i][cnt],j-i+1),然后修改j-1次能做到的,j此也能做到,dp[i][j]=max(dp[i][j],dp[i][j-1])。

    然后我们用前缀和数组sum预处理出区间[i,j]内1的数量,然后我们枚举每个区间如果当前区间能变成全0,就记录当前0的数量j-i+1对应的右边的1的数量dp[j+1][k-sum[j]+sum[i-1]]。

    然后再将字符串颠倒,再求一遍就得到了连续1在0右边是最长0和最长1的对应关系,最后按照最开始所说的求最大值即可

    1. //#include<__msvc_all_public_headers.hpp>
    2. #include
    3. using namespace std;
    4. const int N = 3005;
    5. string s;
    6. int n, k;
    7. int dp[N][N];
    8. int ma[N];
    9. int sum[N];
    10. void init()
    11. {//每次dp前初始化
    12. for (int i = 0; i <= n; i++)
    13. {
    14. sum[i] = 0;
    15. for (int j = 0; j <= n; j++)
    16. {
    17. dp[i][j] = 0;
    18. }
    19. }
    20. }
    21. void solve()
    22. {
    23. init();
    24. for (int i = n - 1; i >= 0; i--)
    25. {
    26. if (i != n - 1)
    27. {
    28. for (int j = 0; j < n; j++)
    29. {//大区间从小区间转移
    30. dp[i][j] = dp[i + 1][j];
    31. }
    32. }
    33. int cnt = 0;
    34. for (int j = i; j < n; j++)
    35. {
    36. cnt += (s[j] == '0');
    37. if (cnt > k)
    38. {
    39. break;
    40. }
    41. else
    42. {//[i,n]区间能变成全1
    43. dp[i][cnt] = max(dp[i][cnt], j - i + 1);
    44. }
    45. }
    46. for (int j = 1; j <= k; j++)
    47. {//操作数更大时候可以,更小时候也可以
    48. dp[i][j] = max(dp[i][j], dp[i][j - 1]);
    49. }
    50. }
    51. ma[0] = dp[0][k];//整个字符串全变成1
    52. for (int i = 0; i < n; i++)
    53. {//预处理1的数量
    54. sum[i] = sum[i - 1] + (s[i] == '1');
    55. }
    56. for (int i = 0; i < n; i++)
    57. {
    58. for (int j = i; j < n; j++)
    59. {
    60. if (sum[j] - sum[i - 1] <= k)
    61. {//对于每个连续0的数量,求出其对应的最大1的数量
    62. ma[j - i + 1] = max(ma[j - i + 1], dp[j + 1][k - sum[j] + sum[i - 1]]);
    63. }
    64. }
    65. }
    66. }
    67. int main()
    68. {
    69. ios::sync_with_stdio(false);
    70. cin.tie(0);
    71. int t;
    72. cin >> t;
    73. while (t--)
    74. {
    75. cin >> n >> k;
    76. cin >> s;
    77. for (int i = 0; i <= n; i++)
    78. {
    79. ma[i] = -1;
    80. }
    81. solve();//令0都在1左边求一遍
    82. reverse(s.begin(), s.end());
    83. solve();//令1都在0左边再求一遍
    84. for (int i = 1; i <= n; i++)
    85. {
    86. int ans = 0;
    87. for (int j = 0; j <= n; j++)
    88. {
    89. if (ma[j] != -1)
    90. {//枚举最大值
    91. ans = max(ans, i * j + ma[j]);
    92. }
    93. }
    94. cout << ans << " ";
    95. }
    96. cout << endl;
    97. }
    98. return 0;
    99. }

  • 相关阅读:
    在 Mac M1 上运行 Llama 2 并进行训练
    智能手术机器人起源及应用(一)
    给电脑一键重装系统后找回照片查看器的方法
    一、Vue3基础[组件(props、事件、插槽)]
    [附源码]Python计算机毕业设计Django时间管理软件app
    46. 全排列
    软体机器人与拓扑优化
    Ansible基础及模块
    张量维度改变总结
    Java集合详解
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/132737267