zoukankan      html  css  js  c++  java
  • 【BZOJ】【3930】【CQOI2015】选数

    数论/莫比乌斯反演/快速mu前缀和


      比较容易想到令f[x]表示gcd=x的方案数,令g[x]表示x|gcd的方案数。

      那么有$ g(d)=sum_{d|n} f(n)$,根据莫比乌斯反演,有$f(d)=sum_{d|n} g(n)*mu (frac{n}{d})$

      我一开始想的是算出g以后,倒序枚举 i ,然后枚举 i 的倍数,递推出所有的f[i]……

      因为g比较好算嘛……快速幂一下什么的……

      然而$10^9$直接吓傻我。

      Orz PoPoQQQ

      快速求出mu的前缀和,$10^9$也照样不虚,太神辣

     1 /**************************************************************
     2     Problem: 3930
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:4200 ms
     7     Memory:54024 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 3930
    11 #include<cstdio>
    12 #include<map>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 typedef long long LL;
    23 inline int getint(){
    24     int r=1,v=0; char ch=getchar();
    25     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
    26     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
    27     return r*v;
    28 }
    29 const int N=1e7+1000,P=1e9+7;
    30 const int INF=0x3f3f3f3f;
    31 /*******************template********************/
    32  
    33 int mu[N],prime[1001001],tot;
    34 bool check[N];
    35 map<int,LL> mu_sum;
    36 LL n,d,l,r;
    37 void getmu(){
    38     int n=10000000;
    39     mu[1]=1;
    40     F(i,2,n){
    41         if (!check[i]){
    42             mu[i]=-1;
    43             prime[++tot]=i;
    44         }
    45         F(j,1,tot){
    46             int k=i*prime[j];
    47             if (k>n) break;
    48             check[k]=1;
    49             if (i%prime[j]) mu[k]=-mu[i];
    50             else{
    51                 mu[k]=0;
    52                 break;
    53             }
    54         }
    55     }
    56     F(i,1,n) mu[i]+=mu[i-1];
    57 }
    58 LL Mu_sum(int x){
    59     if (x<=10000000) return mu[x];
    60     if (mu_sum.find(x)!=mu_sum.end())
    61         return mu_sum[x];
    62     LL i,last,re=1;
    63     for(i=1;i<=x;i=last+1){
    64         last=x/(x/i);
    65         if (x/i-1)
    66             re-=(Mu_sum(last)-Mu_sum(i-1))*(x/i-1);
    67     }
    68     return mu_sum[x]=re;
    69 }
    70 LL Pow(LL a,int b){
    71     LL r=1;
    72     for(;b;b>>=1,a=a*a%P) if (b&1) r=r*a%P;
    73     return r;
    74 }
    75 LL solve(){
    76     LL i,last,re=0;
    77     for(i=1;i<=r;i=last+1){
    78         last=min(r/(r/i),l/i?(l/(l/i)):INF);
    79         re+=(Mu_sum(last)-Mu_sum(i-1))*Pow(r/i-l/i,n);
    80         re%=P;
    81     }
    82     return (re%P+P)%P;
    83 }
    84 int main(){
    85 #ifndef ONLINE_JUDGE
    86     freopen("3930.in","r",stdin);
    87     freopen("3930.out","w",stdout);
    88 #endif
    89     n=getint(); d=getint(); l=getint(); r=getint();
    90     l=(l-1)/d; r=r/d;
    91     getmu();
    92     printf("%lld
    ",solve());
    93     return 0;
    94 }
    View Code

      然而$H-L leq 10^5$并没用?不是的……我们可以枚举倍数!

      Orz syk

      记f[i]为gcd恰好为$K*i$的选数方案数,那么对于每一个$i$记$L$为$lceil frac{a}{K*i} ceil $,$R$为$lfloorfrac{b}{K*i} floor$ 那么他的方案数就为$f[i] = (R-L+1) ^ N - (R-L+1)-sum_{a=1,2,dots} f[a*i]$最后的f[1]即为答案。注意若$lceil frac{a}{K} ceil == 1$ 那么全部选K也是一种方案,需要+1。

      (话说好不容易想到一次莫比乌斯反演,然而却做不出来……唉

     1 /**************************************************************
     2     Problem: 3930
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:412 ms
     7     Memory:1664 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 3930
    11 #include<cstdio>
    12 #include<cstring>
    13 #include<cstdlib>
    14 #include<iostream>
    15 #include<algorithm>
    16 #define rep(i,n) for(int i=0;i<n;++i)
    17 #define F(i,j,n) for(int i=j;i<=n;++i)
    18 #define D(i,j,n) for(int i=j;i>=n;--i)
    19 #define pb push_back
    20 using namespace std;
    21 typedef long long LL;
    22 inline int getint(){
    23     int r=1,v=0; char ch=getchar();
    24     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
    25     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
    26     return r*v;
    27 }
    28 const int N=1e5+10,P=1e9+7;
    29 /*******************template********************/
    30  
    31 int d[N],n,K,l,r,a,b;
    32 int Pow(int a,int b){
    33     int r=1;
    34     for(;b;b>>=1,a=(LL)a*a%P) if (b&1) r=(LL)r*a%P;
    35     return r;
    36 }
    37 int main(){
    38 #ifndef ONLINE_JUDGE
    39     freopen("3930.in","r",stdin);
    40     freopen("3930.out","w",stdout);
    41 #endif
    42     n=getint(); K=getint(); a=getint(); b=getint();
    43     l=a/K; r=b/K;
    44     if (a%K) l++;
    45     D(i,100000,1){
    46         int R=r/i,L=l/i;
    47         if (l%i) L++;
    48         if (l<=r){
    49             d[i]=Pow(R-L+1,n);
    50             d[i]=(d[i]-(R-L+1)+P)%P;
    51             for(int j=i+i;j<=100000;j+=i) d[i]=(d[i]-d[j]+P)%P;
    52         }
    53     }
    54     if (l==1) d[1]=(d[1]+1)%P;
    55     printf("%d
    ",d[1]);
    56     return 0;
    57 }
    View Code

    3930: [CQOI2015]选数

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 434  Solved: 222
    [Submit][Status][Discuss]

    Description

     我 们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方 案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要 回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。

    Input

    输入一行,包含4个空格分开的正整数,依次为N,K,L和H。

    Output

    输出一个整数,为所求方案数。

    Sample Input

    2 2 2 4

    Sample Output

    3

    HINT

     样例解释


    所有可能的选择方案:(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)

    其中最大公约数等于2的只有3组:(2, 2), (2, 4), (4, 2)

    对于100%的数据,1≤N,K≤10^9,1≤L≤H≤10^9,H-L≤10^5

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    iOS 上传appstore 一直卡在正在通过 App Store 进行鉴定(转)
    MySQL连接超时处理
    Windows上安装运行Spark
    NSQ端口关系以及注意事项
    C++ http服务
    C++ OpenSSL 之一:编译和使用
    C++ OpenSSL 之二:生成RSA文件
    C++ OpenSSL 之三:生成CSR文件
    C++ OpenSSL 之四:CER转换为PEM
    C++ OpenSSL 之五:生成P12文件
  • 原文地址:https://www.cnblogs.com/Tunix/p/4579314.html
Copyright © 2011-2022 走看看