zoukankan      html  css  js  c++  java
  • [CQOI2015][bzoj3930] 选数 [杜教筛+莫比乌斯反演]

    题面:

    传送门

    思路:

    首先我们把区间缩小到$left[lfloorfrac{L-1}{K} floor,lfloorfrac{R}{K} floor ight]$

    这道题的最特殊的点在于,他的gcd不是两个数的而是多个数的,是一坨sigma

    但是,我们发现它依然可以反演

    令$fleft(i ight)$为区间$left[l,r ight]$内选出$n$个数,总计$gcd=i$的方法数

    令$gleft(i ight)$为区间$left[l,r ight]$内选出$n$个数,总计$i|gcd$的方法数

    那么依旧满足$g(d)=sum_{d|i}fleft(i ight)$,反演后得到$f(d)=sum_{d|i}muleft(frac id ight)gleft(i ight)$

    因此$fleft(d ight)=sum_{i=1}^{frac nd}left(lfloorfrac Rd floor-lfloorfrac Ld floor ight)^n$

    答案即为对于缩小过的$L,R$,$fleft(1 ight)$的值

    因为后半部分的可以用快速幂加数论分块做到$Oleft(sqrt n ight)$

    所以前半部分杜教筛$mu$即可

    Code:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<map>
     6 #define ll long long
     7 using namespace std;
     8 inline ll read(){
     9     ll re=0,flag=1;char ch=getchar();
    10     while(ch>'9'||ch<'0'){
    11         if(ch=='-') flag=-1;
    12         ch=getchar();
    13     }
    14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    15     return re*flag;
    16 }
    17 ll pri[2000010],tot=0,mu[2000010],n,K,L,R;bool vis[2000010];
    18 ll MOD=1e9+7;
    19 void init(){
    20     ll i,j,k;mu[1]=1;
    21     for(i=2;i<=2000000;i++){
    22         if(!vis[i]){
    23             pri[++tot]=i;mu[i]=-1;
    24         }
    25         for(j=1;j<=tot;j++){
    26             k=i*pri[j];if(k>2000000) break;
    27             vis[k]=1;
    28             if(i%pri[j]==0){
    29                 mu[k]=0;break;
    30             }
    31             mu[k]=-mu[i];
    32         }
    33     }
    34     for(i=2;i<=2000000;i++) mu[i]=mu[i-1]+mu[i];
    35 }
    36 ll sum1(ll x){return x*(x+1)/2;}
    37 map<ll,ll>m;
    38 ll S2(ll x){
    39     if(x<=2000000) return mu[x];
    40     ll re=1,i,j;
    41     if(m[x]) return m[x];
    42     for(i=2;i<=x;i=j+1){
    43         j=x/(x/i);
    44         re-=((j-i+1)*S2(x/i))%MOD;
    45         re=(re+MOD)%MOD;
    46     }
    47     return m[x]=re;
    48 }
    49 ll ppow(ll a,ll b){
    50     ll re=1;
    51     while(b){
    52         if(b&1) re=re*a%MOD;
    53         a=a*a%MOD;b>>=1;
    54     }
    55     return re%MOD;
    56 }
    57 int main(){
    58     init();
    59     n=read();K=read();L=read();R=read();
    60     L=(L-1)/K;R=R/K;
    61     ll i,j;ll ans=0;
    62     for(i=1;i<=R;i=j+1){
    63         j=R/(R/i);
    64         if(i<=L) j=min(j,L/(L/i));
    65         ans=(ans+(S2(j)-S2(i-1)+MOD)%MOD*ppow(R/i-L/i,n)%MOD)%MOD;
    66     }
    67     printf("%lld
    ",ans);
    68 }
  • 相关阅读:
    python可视化---plot()函数
    蜂鸣器的相关知识及简单应用
    将一个文件夹中多个视频的视频帧保存在多个文件夹下
    键盘按键控制程序的简单案例
    Tkinter模块的详细总结
    控制LED灯发光
    python socket 套接字编程 单进程服务器 实现多客户端访问
    python 报错RuntimeError: dictionary changed size during iteration
    HTTP请求行、请求头、请求体详解(转)
    python UDP套接字通信
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8530366.html
Copyright © 2011-2022 走看看