• Codeforces Round #813 (Div. 2) E. LCM Sum (lcm 离线+树状数组)


    题目

    给定t(t<=1e5)组询问,每次给定l,r(1<=l<=r<=2e5,l+2<=r),

    询问在[l,r]之间互不相等的i,j,k(ii+j+k的三元组(i,j,k)的数量

    和easy的区别仅在于询问数量,easy是5组询问,允许离线

    思路来源

    看了红名爷的代码就会了

    题解

    首先直接统计不好统计,然后考虑用总的减去不满足条件的

    对不满足条件的小范围打了个表,发现只有两种情况,

    1. lcm(i,j,k)=k,即i|k且j|k,所以枚举k的约数统计

    2. lcm(i,j,k)=2k,此时有i和j均是2k的因子且i和j在2的因子个数之和比k多一个的结论,可惜这个结论没啥用,进一步观察打表结果发现,只可能是(3,4,6)和(6,10,15)这两种情况及其倍数,这就可以做了

    easy的时候搞了一个指针每次暴力扫到合法的位置,O(qnlogn)

    hard就是把询问离线,指针扫的时候插到BIT上,相当于(i,j,k),枚举k使之不超过当前r的限制,把对于i来说当前满足j的个数插入在i的位置,查询时只查满足条件的段,O(qlogq+n(logn)^2)

    BIT常见套路,然而看着1e5组询问,值域2e5,

    赛中过了easy之后全在想怎么莫队,然后发现会转移右端点不会转移左端点,过于睿智

    bonus:想想1log咋做

    代码1(easy)

    1. #include
    2. using namespace std;
    3. const int N=2e5+10;
    4. typedef long long ll;
    5. int t,l,r,L,R;
    6. vector<int>fac[N];
    7. void init(){
    8. for(int i=1;i
    9. for(int j=2*i;j
    10. fac[j].push_back(i);
    11. }
    12. }
    13. }
    14. ll C2(int x){
    15. return 1ll*x*(x-1)/2;
    16. }
    17. ll C3(int x){
    18. return 1ll*x*(x-1)*(x-2)/6;
    19. }
    20. int main(){
    21. init();
    22. scanf("%d",&t);
    23. while(t--){
    24. scanf("%d%d",&l,&r);
    25. ll ans=C3(r-l+1);
    26. for(int k=l+2;k<=r;++k){
    27. int id=0;
    28. while(idsize() && fac[k][id]
    29. if(id>=fac[k].size())continue;
    30. int sz=fac[k].size()-id;
    31. ans-=C2(sz);
    32. }
    33. L=(l+2)/3,R=r/6;//(3,4,6)
    34. ans-=max(0,R-L+1);
    35. L=(l+5)/6,R=r/15;//(6,10,15)
    36. ans-=max(0,R-L+1);
    37. printf("%lld\n",ans);
    38. }
    39. return 0;
    40. }

    代码2(hard)

    1. #include
    2. using namespace std;
    3. const int N=2e5+10;
    4. typedef long long ll;
    5. int t,L,R,tr[N];
    6. ll ans[N];
    7. vector<int>fac[N];
    8. struct node{
    9. int l,r,id;
    10. }e[N];
    11. bool operator<(node a,node b){
    12. return a.r
    13. }
    14. void add(int x,int v){
    15. for(int i=x;i
    16. tr[i]+=v;
    17. }
    18. }
    19. int sum(int x){
    20. int ans=0;
    21. for(int i=x;i;i-=i&-i){
    22. ans+=tr[i];
    23. }
    24. return ans;
    25. }
    26. void init(){
    27. for(int i=1;i
    28. for(int j=2*i;j
    29. fac[j].push_back(i);
    30. }
    31. }
    32. }
    33. ll C2(int x){
    34. return 1ll*x*(x-1)/2;
    35. }
    36. ll C3(int x){
    37. return 1ll*x*(x-1)*(x-2)/6;
    38. }
    39. int main(){
    40. init();
    41. scanf("%d",&t);
    42. for(int i=1;i<=t;++i){
    43. scanf("%d%d",&e[i].l,&e[i].r);
    44. e[i].id=i;
    45. }
    46. sort(e+1,e+t+1);
    47. int k=1;
    48. for(int i=1;i<=t;++i){
    49. int id=e[i].id,l=e[i].l,r=e[i].r;
    50. ans[id]=C3(r-l+1);
    51. for(;k<=r;++k){
    52. int sz=fac[k].size();
    53. for(int i=0;i
    54. add(fac[k][i],sz-1-i);
    55. }
    56. }
    57. ans[id]-=sum(r)-sum(l-1);
    58. L=(l+2)/3,R=r/6;//(3,4,6)
    59. ans[id]-=max(0,R-L+1);
    60. L=(l+5)/6,R=r/15;//(6,10,15)
    61. ans[id]-=max(0,R-L+1);
    62. }
    63. for(int i=1;i<=t;++i){
    64. printf("%lld\n",ans[i]);
    65. }
    66. return 0;
    67. }

  • 相关阅读:
    leetCode 198.打家劫舍 动态规划
    hive创建分区表
    认识垃圾回收
    同时申请发明专利和实用新型专利的好处
    5年没发paper,学术论文写到头秃...
    一文2500字手把手教你使用jmeter进行分布式压力测试【保姆级教程】
    Could not find androidx.camera:camera-view
    为Qt应用程序的用户添加帮助文档
    SA8155 QNX 命令
    STL容器——vector
  • 原文地址:https://blog.csdn.net/Code92007/article/details/126360154