• Codeforces Round #808 (Div. 2) C【二分】【贪心】【反向贪心】


     一开始自己想贪心思路的时候想错了,导致了错误的结果。

    这是我想的错误贪心思路,留在这里做个纪念吧, 写的时间还不少,

    还认真去调了点bug

     

    1. /*
    2. 基础题意:
    3. 该人有一个智商q,
    4. 然后有n个测试,每个测试都有一个难度ai
    5. 编号为i的测试只能再第i天被测。
    6. 如果当前这个人遇到一个测试,但是这个测试的难度系数 >他的智商q,
    7. 那么智商q就要-1
    8. 我们希望能够通过的测试越多越好
    9. 最后输出的字符串中:
    10. "1"表示该测试通过
    11. "0"表示该测试没有通过
    12. */
    13. /*
    14. 我的贪心思路是:
    15. 1.判断要不要挑战比自己智商高的?
    16. 如果我给自己的智商-1,如果在智商 -1的 情况下,
    17. 比自己的(智商低并且挑战日程还在后面的)的挑战数量不变
    18. 那我挑战比自己智商高的就无所谓了 ,
    19. 反之,如果-1后,后面比自己智商低的反而挑战不了,那就抵消了,
    20. 没什么挑战的意义
    21. 2.判断要不要挑战比自己智商低的?
    22. 当前日子到了,遇上了就挑战呗,又不损失什么。
    23. */
    24. /*
    25. one case:
    26. 1
    27. 10 10
    28. 11 1 9 5 10 3 10 10 1 7
    29. ans:
    30. 1111111111
    31. myans:
    32. 0111111111
    33. 这个完全推翻了我的做法的可行性 ,
    34. 所以我的想法是错误的!
    35. */
    36. #include
    37. using namespace std;
    38. const int N=1e5+10;
    39. typedef long long LL;
    40. typedef pair PLL;
    41. LL a[N];
    42. set s;
    43. int main()
    44. {
    45. int t;
    46. cin>>t;
    47. while(t--)
    48. {
    49. int n;
    50. LL q;
    51. cin>>n>>q;
    52. s.clear();
    53. //智商为q
    54. for(int i=1;i<=n;i++)
    55. {
    56. cin>>a[i]; //各测试的难度系数为 a[i]
    57. s.insert({a[i],i});
    58. }
    59. string res;
    60. char o='1',z='0';
    61. for(int i=1;i<=n;i++)
    62. {
    63. s.erase({a[i],i}); //i也表示日期,到期了无论怎样都要删除,方便动态维护
    64. if(q<=0) break;
    65. if(a[i]<=q)
    66. {
    67. res+=o;
    68. }
    69. else if(a[i]>q) //考虑要不要挑战这种智商比自己高的
    70. {
    71. LL qq=q-1;
    72. auto it=s.lower_bound({q,0});
    73. auto jt=s.lower_bound({qq,0});
    74. if((*it).first==q&&it!=s.end())
    75. {
    76. res+=z;
    77. }
    78. else
    79. {
    80. res+=o;
    81. q--;
    82. }
    83. }
    84. }
    85. int l=res.size();
    86. for(int t=1;t<=n-l;t++)
    87. {
    88. res+=z;
    89. }
    90. cout<size()<
    91. cout<
    92. }
    93. return 0;
    94. }

    正确做法一: 反向贪心 【把减少变成增加】

    思路一:
    显然,对于降智比赛,如果我们前面参加的多了那么后面的正常比赛也会变为降智比赛。所以我们的最优策略应该是当最后一天时,我们的智商值恰好为1。(参加完这天的降智比赛即为0)
    所以我们,可以翻转数组,倒着模拟这种情况,从智商值为0开始,如果遇到比当前智商值大的比赛,就参加,并且智商值加一,当智商值等于Q QQ时我们便不再参加。
    ————————————————
    版权声明:本文为CSDN博主「吃一口AC摇摇乐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lucifer1214/article/details/125855257

     

    1. /*
    2. 做法一:
    3. */
    4. #include
    5. using namespace std;
    6. const int N=1e5+10;
    7. int a[N];
    8. int ans[N];
    9. int main()
    10. {
    11. int t;
    12. cin>>t;
    13. while(t--)
    14. {
    15. memset(ans,0,sizeof ans);
    16. int n,q;
    17. cin>>n>>q;
    18. for(int i=1;i<=n;i++)
    19. cin>>a[i];
    20. int qq=0; //当前智商为0
    21. for(int i=n;i>=1;i--)
    22. {
    23. if(a[i]>qq)
    24. {
    25. if(qq
    26. {
    27. qq++;
    28. ans[i]=1;
    29. }
    30. }
    31. else if(a[i]<=qq)
    32. {
    33. ans[i]=1;
    34. }
    35. }
    36. for(int i=1;i<=n;i++)
    37. {
    38. cout<
    39. }
    40. cout<
    41. }
    42. return 0;
    43. }

    正确做法二:二分答案法

    我们用二分法枚举答案中的1。

    记住了,这里遇到之前自己常错的一个点:不能恰好等于!!!

    1. /*
    2. 做法二:二分贪心法
    3. 题目答案虽然是用 1和0表示的,但是也能表现出有多少个1
    4. (所以我们要找最多有多少1)
    5. 这个“最多”可以用二分法枚举 (就是找最大的)
    6. */
    7. #include
    8. using namespace std;
    9. const int N=1e5+10;
    10. int a[N],s[N];
    11. int n,q;
    12. bool check(int num) //整个序列中1的数量是num
    13. {
    14. int skip=n-num; //序列中0的数量也就是能跳过(可以不做)的任务数量
    15. int tq=q;
    16. for(int i=0;i
    17. {
    18. if(tq<=0) //智商值为0了,做不了了
    19. {
    20. s[i]=0;
    21. continue;
    22. }
    23. if(a[i]<=tq) //小于自己的智商,干就完了
    24. {
    25. s[i]=1;
    26. continue;
    27. }
    28. else if(a[i]>tq) //大于自己的智商,看看能不能跳过(skip>0)
    29. {
    30. if(skip>0) //如果属于跳过的,也就是可以跳过
    31. {
    32. s[i]=0;
    33. skip--;
    34. }
    35. else if(skip<=0)//否则就是属于要处理的"1"
    36. {
    37. if(tq>0)
    38. {
    39. s[i]=1;
    40. tq--;
    41. }
    42. }
    43. }
    44. }
    45. int co=0; //看看最终的序列中1的个数是否=num
    46. for(int i=0;i
    47. {
    48. if(s[i]==1)
    49. {
    50. co++;
    51. }
    52. }
    53. return co>=num; //我一开始写的恰好等于,也就是return co==num,WA了
    54. //之前也遇到过类似的错误,不能恰好等于
    55. }
    56. void solve()
    57. {
    58. cin>>n>>q;
    59. for(int i=0;i
    60. scanf("%d",&a[i]);
    61. if(q>=n) //如果q本身就大于等于n个的n
    62. {
    63. for(int i=0;i
    64. s[i]=1;
    65. }
    66. else
    67. {
    68. int l=0,r=n;
    69. while(l
    70. {
    71. int mid=(l+r+1)>>1;
    72. if(check(mid)) l=mid; //往右找最大的
    73. else r=mid-1;
    74. }
    75. //最终l是最终的结果
    76. //cout<<"l is "<
    77. check(l);
    78. }
    79. for(int i=0;i
    80. cout<
    81. cout<
    82. }
    83. int main()
    84. {
    85. int t;
    86. cin>>t;
    87. while(t--)
    88. {
    89. solve();
    90. }
    91. return 0;
    92. }

     

     

  • 相关阅读:
    【深度学习笔记】计算机视觉——图像增广
    linux中的chmod改变权限、修改bigbig.txt文件使其所属主用户只有读权限、修改bigbig.txt文件使其所属组用户具有写权限
    【Vue】组件之间的方法调用
    接口测试入门
    CSS中三栏布局的实现
    Docker深入讲解
    Leecode专题——回溯系列
    揭秘得物客服IM全链路通信过程
    【Spring】MyBatis(缓存机制、二级缓存、插件)面试题
    如何在.NET电子表格应用程序中创建流程图
  • 原文地址:https://blog.csdn.net/bei2002315/article/details/126333034