zoukankan      html  css  js  c++  java
  • 【HAOI2011】problem b

    数论好劲啊

    原题:

    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

    1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

    gcd出现,基本上可以确定是数论了

    最开始脑补了一下感觉应该是容斥之类的东西,去网上搜题解,果然是容斥(反演算是建立在整除上的容斥?

    然后补习po姐的ppt,发现这题居然是第一道例题

    补习了一下反演,这次和第一次学的时候不一样,证明什么的都扔掉,直接记公式应用(应试套路暴力硬肛

    然后实力提升了果然不一样,现在拿起笔推公式也有感觉了

    题目中要求gcd(x,y)=k的xy对数,这个可以用一个函数表示:f(k)=cnt(gcd(x,y)=k)

    然后gcd是建立在整除上的,所以可以往莫比乌斯反演的方向想,尝试构造函数F(i)=cnt(i|gcd(x,y))(我说的推导过程这么有代入感其实我靠自己是根本推不出来的hhh

    于是(我发现这个公式显示好像有点问题= =另存到本地即可查看)

    然后就可以使用反演辣,直接从中反演出f(i)

    F(i)比较容易计算

    枚举i(实际上是k)的倍数即可算出答案

    但是酱紫做是O(N)的,会T掉(还有n个询问)

    因为可能会有很多是相等的,所以可以直接搞一个miu的前缀和,把相等的F(i)乘上miu的前缀和即可

    怎么求相等的F(i)呐,每次前缀和的右端点是min(n/(n/i),m/(m/i)),左端点是上一次的右端点即可

    (我说不下去了具体还是看po姐的ppt理解吧

    写代码的时候又出现傻逼错误了,不过这一次很快召唤了数学大神syq帮忙查看,所以很快就找到问题了

    summiu[1]没设初值……妙啊……

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 #define ll long long
     8 int rd(){int z=0,mk=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mk;
    12 }
    13 int n;
    14 int prm[51000],ptt=0;
    15 bool flg[51000];
    16 int miu[51000],smmiu[51000];
    17 void slct(){
    18     memset(flg,0,sizeof(flg));
    19     miu[1]=1,smmiu[1]=1;
    20     for(int i=2;i<=50000;++i){
    21         if(!flg[i])  prm[++ptt]=i,miu[i]=-1;
    22         for(int j=1;prm[j]*i<=50000 && j<=ptt;++j){
    23             flg[prm[j]*i]=true;
    24             if(!(i%prm[j])){  miu[i*prm[j]]=0;  break;}
    25             miu[prm[j]*i]=-miu[i];
    26         }
    27         smmiu[i]=miu[i]+smmiu[i-1];
    28     }
    29 }
    30 ll cclt(int n,int m,int k){
    31     n/=k,m/=k;
    32     if(n>m)  swap(n,m);
    33     ll bwl=0,tmp;
    34     for(int i=1;i<=n;i=tmp+1){
    35         tmp=min(n/(n/i),m/(m/i));
    36         bwl+=(ll)(n/i)*(m/i)*(smmiu[tmp]-smmiu[i-1]);
    37     }
    38     return bwl;
    39 }
    40 int main(){//freopen("ddd.in","r",stdin);
    41     slct();
    42     cin>>n;
    43     int a,b,c,d,k;
    44     while(n--){
    45         a=rd(),b=rd(),c=rd(),d=rd(),k=rd();
    46         printf("%I64d
    ",cclt(b,d,k)+cclt(a-1,c-1,k)-cclt(b,c-1,k)-cclt(a-1,d,k));
    47     }
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    移动H5页面微信支付踩坑之旅(微信支付、单页面路由模拟、按钮加锁、轮询等常见功能)
    EDM模板编写踩坑指南(持续更新中)
    7天内我面试了10家公司,如何从命中率0%到命中率至70%?
    codewars.DNA题目几种解法分析(字符串替换)
    webpack+react搭建环境
    手机端访问网页 js根据浏览器区别转入手机端网址的URL
    树状数组————(神奇的区间操作)蒟蒻都可以看懂,因为博主就是个蒟蒻
    DFS————从普及到IOI(暴力骗分小能手)
    Manacher(马拉车)————O(n)回文子串
    离散化————实现梦想的算法
  • 原文地址:https://www.cnblogs.com/JSL2018/p/6481027.html
Copyright © 2011-2022 走看看