2019牛客国庆集训派对day2 K 2018

我这里在原题目上面加了扩充

修改:将2018改为x(x不是很大 ,其他题面内容不变
方法:首先将x分解质因子,变为 x = p 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p n e n x=p_{1}^{e1}*p_{2}^{e2}*...*p_{n}^{en} x=p1e1p2e2...pnen的形式
在[a,b]区间我们枚举 %x的余数 i ∈ [ 0 , x − 1 ] i\in [0,x-1] i[0,x1] ,.然后将 i 里x的质因子的数除掉,不够的乘起来,最后得到一个数y,相当于找到最小的y满足 i ∗ y % x = 0 i*y\%x = 0 iy%x=0,则i对应的是[c,d]里y倍数的数量
单次询问时间复杂度: O ( x ∗ x p r i 数 量 ) O(x*x_{pri数量}) O(xxpri)
将下面代码修改下可以过掉那题(文章最后面)。

代码如下

#include <bits/stdc++.h>
#define LL long long
const int N = 2e5+5;
using namespace std;
int x,a,b,c,d;
LL s1(int l,int r,int mo){//得到[l,r]里%x==mo的数量
    if(mo==0)mo=x;
    int ans=r/x - (l-1)/x;
    if(r%x>=mo)ans++;
    if((l-1)%x>=mo)ans--;
    return ans;
}
LL s2(int l,int r,int mo){//得到[l,r]为mo倍数的数量
    return r/mo-(l-1)/mo;
}
int pr[100][2],len;
int main(){
    cin>>x>>a>>b>>c>>d;
    int lx=x;
    for(int i=2;i*i<=lx;i++)
        if(lx%i==0){
            pr[++len][0]=i;
            while(lx%i==0)
                pr[len][1]++,lx/=i;
        }
    if(lx!=1)pr[++len][0]=lx,pr[len][1]=1;

    LL ans=s1(a,b,0)*(d-c+1);//特判i=0
    for(int i=1;i<x;i++){
        int y=1,li=i;
        for(int j=1;j<=len;j++){
            int js=0;
            while(li%pr[j][0]==0)
                li/=pr[j][0],js++;
            if(js>=pr[j][1])js=0;
            else js=pr[j][1]-js;
            while(js--)
                y*=pr[j][0];
        }
        ans+=s1(a,b,i)*s2(c,d,y);
    }
    printf("%lld\n",ans);
    return 0;
}
/**
2018 1 2 1 2018
2018 1 2018 1 2018
2018 1 1000000000 1 1000000000
*/

能AC这题的代码

#include <bits/stdc++.h>
#define LL long long
const int N = 2e5+5;
using namespace std;
int x,a,b,c,d;
LL s1(int l,int r,int mo){//得到[l,r]里%x==mo的数量
    if(mo==0)mo=x;
    int ans=r/x - (l-1)/x;
    if(r%x>=mo)ans++;
    if((l-1)%x>=mo)ans--;
    return ans;
}
LL s2(int l,int r,int mo){//得到[l,r]为mo倍数的数量
    return r/mo-(l-1)/mo;
}
int pr[100][2],len;
int main(){
    x=2018;
    int lx=x;
    for(int i=2;i*i<=lx;i++)
        if(lx%i==0){
            pr[++len][0]=i;
            while(lx%i==0)
                pr[len][1]++,lx/=i;
        }
    if(lx!=1)pr[++len][0]=lx,pr[len][1]=1;
    while(cin>>a>>b>>c>>d){
        LL ans=s1(a,b,0)*(d-c+1);//特判i=0
        for(int i=1;i<x;i++){
            int y=1,li=i;
            for(int j=1;j<=len;j++){

                int js=0;
                while(li%pr[j][0]==0)
                    li/=pr[j][0],js++;
                if(js>=pr[j][1])js=0;
                else js=pr[j][1]-js;
                while(js--)
                    y*=pr[j][0];
            }
           // printf("y=%d\n",y);
           //printf("i=%d %d %d\n",i,y,s1(a,b,i)*s2(c,d,y));
            ans+=s1(a,b,i)*s2(c,d,y);
        }
        printf("%lld\n",ans);
    }


    return 0;
}
/**

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值