• 2022杭电多校八 1005-Ironforge(二分+区间暴力)


    题目链接:杭电多校8 - Virtual Judge

    题目:

     样例输入:

    1. 1
    2. 5 5
    3. 7 1 6 6 14
    4. 7 2 3 2
    5. 1 2
    6. 1 4
    7. 3 5
    8. 5 1
    9. 3 1

    样例输出:

    1. Yes
    2. No
    3. Yes
    4. Yes
    5. Yes

    题意:一条链,每个点上有一个数 ,每条边上有一个质数 。一开始在某个点上,有一个空背包,走到一个 点上可以把它的质因子放进背包,一条边如果背包里有那个质数就可以走。多组询问求从 x 出发能否走到 y。

    分析:其实就是要我们求从每个点出发能够扩展到的最左和最右区域,对于每组询问u,v我们只需要判断v是否在u所扩展到的区域内就可以了。

    我们可以先暴力求解一下每个点只向左走可以扩展到的左边界,当然这并不是最后的左边界,因为最后的左边界有可能是我们先向右扩展一段距离再向左扩展所能达到的位置。下面我来分析一下如何向左扩展,肯定不会是一点技巧没用的纯暴力。

    对于一个点i,我们先判断他能否到达第i-1个点,如果不能,那么l[i]就等于i,否则就先令l[i]=l[i-1],然后再向左暴力扩展,每能到达一个位置x,就令l[i]=l[x],怎么判断能否到达一个位置x呢?也就是说如何知道区间[x+1,i]内的数的质因子分解中是否含有w[x]呢?我们可以用一个vector p[i]存储质因子i所在的位置,然后直接对其进行二分就可以了,只需要保证在质因子p[w[x]]中存在区间[x+1,i]的数即可。由于我们向左扩展的时候利用到了前面已经更新好的左边界,所以均摊下来复杂度就是O(1)的,当左边界全部预处理好了之后我们从右向左直接暴力向左向右扩展边界求得每个数最终的左右边界,什么时候算是最终的左右边界呢?就是说某一时刻我在区间[l[i],r[i]]内的数的质因子既不包含w[r[i]],也不包含w[l[i]-1],这个时候我就无法继续向两端扩展了,这也就是我最后能扩展到的左右边界了。

    最后再说一个技巧,就是说我们可以最后向所有的质因子vector中压入一个无穷大的数,这样做的目的是防止利用lower_bound函数进行二分时因为vector为空而导致的越界问题,加入一个数后就不会再产生这种问题。

    这道题我们需要学会如何知道一个区间的数质因子分解中是否存在某个质因子,就是利用vector p[i]存储质因子i出现过的位置,如果我们从前往后进行质因子分解,那么位置的顺序自动就是拍好序的,等到我们需要判断某个质因子是否在某个区间中出现过的时候我们直接对这个质因子的vector直接二分位置即可。这个还是比较有用的,当时在考试的时候就没有想到这样的方法。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. using namespace std;
    10. const int N=2e5+10;
    11. int a[N],w[N];
    12. vector<int>p[N];
    13. int l[N],r[N];
    14. int main()
    15. {
    16. int T;
    17. cin>>T;
    18. while(T--)
    19. {
    20. for(int i=1;i<=200000;i++) p[i].clear();
    21. int n,m;
    22. scanf("%d%d",&n,&m);
    23. for(int i=1;i<=n;i++)
    24. scanf("%d",&a[i]);
    25. for(int i=1;i
    26. scanf("%d",&w[i]);
    27. for(int i=1;i<=n;i++)
    28. {
    29. for(int j=2;j*j<=a[i];j++)
    30. {
    31. if(a[i]%j==0)
    32. {
    33. p[j].push_back(i);
    34. while(a[i]%j==0) a[i]/=j;
    35. }
    36. }
    37. if(a[i]!=1) p[a[i]].push_back(i);
    38. }
    39. for(int i=1;i<=200000;i++) p[i].push_back(0x3f3f3f3f);//防止越界
    40. //处理左边界
    41. l[1]=1;
    42. for(int i=2;i<=n;i++)
    43. {
    44. int id=*lower_bound(p[w[i-1]].begin(),p[w[i-1]].end(),i);
    45. if(id==i)
    46. l[i]=l[l[i-1]];
    47. else
    48. {
    49. l[i]=i;
    50. continue;
    51. }
    52. while(l[i]>1)
    53. {
    54. int tid=*lower_bound(p[w[l[i]-1]].begin(),p[w[l[i]-1]].end(),l[i]);
    55. if(tid<=i) l[i]=l[l[i]-1];
    56. else break;
    57. }
    58. }
    59. for(int i=n;i>=1;i--)
    60. {
    61. bool flag=true;
    62. r[i]=i;
    63. while(flag)
    64. {
    65. flag=false;
    66. //向右扩展
    67. while(r[i]
    68. {
    69. int tid=*lower_bound(p[w[r[i]]].begin(),p[w[r[i]]].end(),l[i]);
    70. if(tid==0x3f3f3f3f) break;
    71. if(tid<=r[i])
    72. {
    73. r[i]=r[r[i]+1];
    74. flag=true;
    75. }
    76. else break;
    77. }
    78. //向左扩展
    79. while(l[i]>1)
    80. {
    81. int tid=*lower_bound(p[w[l[i]-1]].begin(),p[w[l[i]-1]].end(),l[i]);
    82. if(tid==0x3f3f3f3f) break;
    83. if(tid<=r[i])
    84. {
    85. l[i]=l[l[i]-1];
    86. flag=true;
    87. }
    88. else break;
    89. }
    90. }
    91. }
    92. for(int i=1;i<=m;i++)
    93. {
    94. int u,v;
    95. scanf("%d%d",&u,&v);
    96. if(v>=l[u]&&v<=r[u]) puts("Yes");
    97. else puts("No");
    98. }
    99. }
    100. return 0;
    101. }

  • 相关阅读:
    协程学习(一)--初识协程
    【十分钟】manim安装 2022
    C语言推荐书籍
    利用Redis实现全局唯一ID
    OSPF —— LSA-3
    YOLOv5改进实战 | GSConv + SlimNeck双剑合璧,进一步提升YOLO!
    Kubeadm方式搭建K8S集群
    SpringBoot之@ConfigurationProperties和@Value用法详解
    Vue中props的默认值defalut使用this时的问题
    NBU计算机大三下期末考
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/126305179