Gym - 101982B(Coprime Integers)容斥 / 莫比乌斯反演

题意:

给定两个区间[a,b][c,d]x \in[a,b],y \in[c,d],问有多少对x、y互质。

题解:

赛场上别的队都是一发A,以为很容易,搞了半天没弄出来,赛后才知道模板书上有一道一模一样的题。

不过模板书给的代码是莫比乌斯反演。

赛后百度了一下题解,发现也可以用容斥做,思路和我赛场上的思路一样,但由于赛场上写容斥的时候想到dfs,感觉复杂度太高,而且剩下时间不多了,就自动开启了自闭模式。

下面给出两种题解:

一、容斥 
二、莫比乌斯反演

一、容斥 

先对素数打个表,打到1e7。

这种方法计算的是两个区间中不互质的个数,然后用总数减去不互质的个数得到答案,下面分析如何计算不互质的个数。

首先我们必须知道一点:如果两个数不互质,那么这两个数唯一因式分解后,一定会有相同的素数因子,那么我们从这些素数因子入手,包含素数因子p的数可以是:p、2p、3p……,计算一下两个区间中分别包含多少个这样的数。

int t1=b/p-a/p;
if(a%p==0) t1++;

int t2=d/p-c/p;
if(c%p==0) t2++;

t1*t2就是:因为包含素数因子p而不互质的个数。

举个例子:两个区间[3,7]和[5,12];

区间[3,7]={3,4,5,6,7};
区间[5,12]={5,6,7,8,9,10,11,12};

根据素数表:{2,3,5,7,11,13……}

对于第一个素数2,2的倍数有1*2,2*2,3*2……
t1=2={4,6},t2=4={6,8,10,12},这两个集合里的数两两都不互质,并且任一集合和另一集合的补集里的数两两互质。
那么由于两个区间里的数有素因子2而不互质的个数为2*4=8个。
依次类推,之后的素数也这样计算。

这种方法在计算的时候,会出现大量的重复计算,比如6=2*3,在计算素因子2的时候会把6算一遍,计算素因子3的时候又会算一遍6。这时候我们就需要用到容斥了。

重复计算的有任意两个素数的乘积、任意三个素数的乘积……

详细步骤请看代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e7+5;
ll prime[maxn+3];
ll num=0,ans=0;
ll Max,a,b,c,d;
void init()
{
    memset(prime,0,sizeof(prime));
    for(ll i=2; i<=maxn; i++)
    {
        if(!prime[i])
            prime[++num]=i;
        for(ll j=1; j<=num&&prime[j]<=maxn/i; j++)
        {
            prime[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
void dfs(ll x, ll sum,ll nn)
{
    if(nn>Max) return;
    if(sum>b||sum>d) return;
    
    ll t1=d/sum-c/sum;
    if(c%sum==0) t1++;
    ll t2=b/sum-a/sum;
    if(a%sum==0) t2++;
    
    if(nn%2==1) ans+=t1*t2;
    else ans-=t1*t2;
    
    for(ll i=x+1; i<=num; i++)
    {
        ll temp=sum*prime[i];
        if(temp>b||temp>d) return;
        dfs(i,temp,nn+1);
    }
    return ;
}
int main()
{
    // freopen("in.txt","r",stdin);
    init();
    scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    Max=max(b,d);
    for(ll i=1; i<=num; i++)
    {
        if(prime[i]>b||prime[i]>d) break;
        dfs(i,prime[i],1);
    }
    ll ss=(d-c+1)*(b-a+1);
    printf("%lld",ss-ans);

    return 0;
}

 

二、莫比乌斯反演 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7;
bool check[maxn+10];
int prime[maxn+10];
int mu[maxn+10];

void Moblus()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i = 2; i <= maxn; i++)
    {
        if(!check[i])
        {
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j = 0; j < tot; j++)
        {
            if(i*prime[j] > maxn) break;
            check[i*prime[j]] = true;
            if(i%prime[j] == 0)
            {
                mu[i*prime[j] == 0];
                break;
            }
            else
            {
                mu[i*prime[j]] = -mu[i];
            }
        }
    }
}
int sum[maxn+10];
ll solve(int n,int m)
{
    ll ans = 0;
    if(n > m) swap(n,m);
    for(int i = 1, la = 0; i <= n; i = la + 1)
    {
        la = min(n/(n/i),m/(m/i));
        ans +=(ll)(sum[la]-sum[i-1])*(n/i)*(m/i);
    }
    return ans;
}
int main()
{
    // freopen("in.txt","r",stdin);
    Moblus();
    sum[0] = 0;
    for(int i = 1; i <= maxn ; i++)
    {
        sum[i] = sum[i-1] + mu[i];
    }
    int a,b,c,d,k=1;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    ll ans = solve(b/k,d/k) - solve((a-1)/k,d/k) - solve(b/k,(c-1)/k) + solve((a-1)/k,(c-1)/k);
    printf("%lld",ans);

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wandb: Tracking run with wandb version 0.15.5 wandb: W&B syncing is set to `offline` in this directory. wandb: Run `wandb online` or set WANDB_MODE=online to enable cloud syncing. /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/gym/envs/registration.py:556: UserWarning: WARN: The environment Ant-v2 is out of date. You should consider upgrading to version `v4`. f"The environment {id} is out of date. You should consider " Error compiling Cython file: ------------------------------------------------------------ ... See c_warning_callback, which is the C wrapper to the user defined function ''' global py_warning_callback global mju_user_warning py_warning_callback = warn mju_user_warning = c_warning_callback ^ ------------------------------------------------------------ /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx:92:23: Cannot assign type 'void (const char *) except * nogil' to 'void (*)(const char *) noexcept nogil' Error compiling Cython file: ------------------------------------------------------------ ... See c_warning_callback, which is the C wrapper to the user defined function ''' global py_error_callback global mju_user_error py_error_callback = err_callback mju_user_error = c_error_callback ^ ------------------------------------------------------------ /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx:127:21: Cannot assign type 'void (const char *) except * nogil' to 'void (*)(const char *) noexcept nogil' Compiling /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx because it changed. [1/1] Cythonizing /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx wandb: Waiting for W&B process to finish... (failed 1). wandb: You can sync this run to the cloud by running: wandb: wandb sync /home/zhangmengjie/PID/Python/ERL-Re2-main/wandb/offline-run-20230721_165346-awq1hazo wandb: Find logs at: ./wandb/offline-run-20230721_165346-awq1hazo/logs
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值