zoukankan      html  css  js  c++  java
  • Luogu P2522 [HAOI2011]Problem b

    题意

    (n) 组询问,每组给定 (a,b,c,d,k),求 (sumlimits_{i=a}^{b}sumlimits_{j=c}^{d}[gcd(i,j)=k])

    ( exttt{Data Range:}1leq n,kleq 5 imes 10^4,1leq aleq bleq 5 imes 10^4,1leq cleq dleq 5 imes 10^4)

    题解

    首先考虑二维差分一下,发现我们只需要求出类似于 (sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]) 的东西就好了(这里的 (n) 不再是数据组数)

    然后考虑推一下式子

    [sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{i=1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{j=1}^{leftlfloorfrac{m}{k} ight floor}[gcd(i,j)=1] ]

    然后发现可以莫反一下

    [sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{i=1}^{leftlfloorfrac{n}{k} ight floor}sumlimits_{j=1}^{leftlfloorfrac{m}{k} ight floor}sumlimits_{dmidgcd(i,j)}mu(d) ]

    然后交换一下求和变量得到

    [sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{dmidgcd(i,j)}mu(d)leftlfloorfrac{n}{dk} ight floorleftlfloorfrac{m}{dk} ight floor ]

    然后线性筛一下 (mu) 的前缀和就可以整除分块做了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=2e5+51;
    ll ptot,n,u,v,w,x,kk;
    ll np[MAXN],prime[MAXN],mu[MAXN],prefix[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline void sieve(ll limit)
    {
        np[1]=mu[1]=1;
        for(register int i=2;i<=limit;i++)
        {
            if(!np[i])
            {
                prime[++ptot]=i,mu[i]=-1;
            }
            for(register int j=1;i*prime[j]<=limit;j++)
            {
                np[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
        for(register int i=1;i<=limit;i++)
        {
            prefix[i]=prefix[i-1]+mu[i];
        }
    }
    inline ll calc(ll n,ll m)
    {
        ll res=0;
        for(register int l=1,r;l<=min(n,m);l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            res+=(prefix[r]-prefix[l-1])*(n/l/kk)*(m/l/kk);
        }
        return res;
    }
    int main()
    {
        n=read(),sieve(2e5+10);
        for(register int i=1;i<=n;i++)
        {
            u=read(),v=read(),w=read(),x=read(),kk=read();
            printf("%d
    ",calc(v,x)-calc(u-1,x)-calc(v,w-1)+calc(u-1,w-1));
        }
    }
    
  • 相关阅读:
    【Java并发编程】:使用synchronized获取互斥锁
    【Java并发编程】:Runnable和Thread实现多线程的区别
    【Java并发编程】:volatile变量修饰符
    【Java并发编程】:守护线程与线程阻塞的四种情况
    【Java并发编程】:线程挂起、恢复与终止
    【Java并发编程】:线程中断
    redis配置详细解析
    redis常用命令
    centos7上安装redis
    redis简介
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13687511.html
Copyright © 2011-2022 走看看