zoukankan      html  css  js  c++  java
  • [CQOI2015]选数

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    2 2 2 4
    输出样例#1:
    3

    说明

    样例解释

    所有可能的选择方案:(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

    此题有巧解

    首先将L/k,R/k,gcd=k/k=1

    令f(x)为gcd=x的方案数

    F(i)为x能被i整除的方案数

    F(i)=∑df(d)    (i|d)

    反演得f(d)=∑iμ(i/d)F(i)  (d|i)

    f(1)=∑μ(i)F(i)    (1<=i<=H)

    =∑μ(i)([r/i]-[(l-1)/i])^n

    可知当i>H-L时,[r/i]-[(l-1)/i]等于1或0,所以可以去掉指数

    f(1)=∑μ(i)([r/i]-[(l-1)/i])+∑μ(j)([r/j]-[(l-1)/j])^n         (H-L+1<=i<=H,1<=j<=H-L)

    因为H-L很小,直接枚举加快速幂搞定,对于左边

    ∑μ(i)([r/i]-[(l-1)/i])                  (H-L+1<=i<=H)

    =∑μ(i)([r/i]-[(l-1)/i])-∑μ(j)([r/j]-[(l-1)/j])     (1<=i<=H,1<=j<=H-L)

    右边快速幂,而∑μ(i)([r/i]-[(l-1)/i])可以等价于取一个数,使gcd=1的方案数,显然只有当L=1时+1

    复杂度为O((H-L)*log(n))

    似乎此题还可以用递推??

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 int Mod=1000000007;
     7 typedef long long lol;
     8 bool vis[100001];
     9 lol mu[100001],r,l,n,k,ans;
    10 int tot,prime[100001];
    11 lol qpow(lol x,lol y)
    12 {
    13     lol res=1;
    14     while (y)
    15     {
    16         if (y%2==1)
    17         {
    18             res=(res*x)%Mod;
    19         }
    20         x=(x*x)%Mod;
    21         y=y/2;
    22     }
    23     return res;
    24 }
    25 void mobius()
    26 {lol i,j;
    27 mu[1]=1;
    28     for (i=2;i<=r-l;i++)
    29     {
    30         if (vis[i]==0)
    31         {
    32             tot++;
    33             prime[tot]=i;
    34             mu[i]=-1;
    35         }
    36         for (j=1;j<=tot,i*prime[j]<=r-l;j++)
    37          {
    38              vis[i*prime[j]]=1;
    39              if (i%prime[j]==0)
    40              {
    41                  mu[i*prime[j]]=0;
    42                  break;
    43             }
    44                  mu[i*prime[j]]=-mu[i];
    45          }
    46     }
    47 }
    48 int main()
    49 {int i;
    50     cin>>n>>k>>l>>r;
    51     l=(l+k-1)/k;r=r/k;
    52     mobius();
    53     for (i=1;i<=r-l;i++)
    54     {
    55       ans=(ans+mu[i]*qpow(r/i-(l-1)/i,n)%Mod)%Mod;    
    56     }
    57     if (l==1) ans++;
    58     for (i=1;i<=r-l;i++)
    59     {
    60       ans=(ans-mu[i]*(r/i-(l-1)/i))%Mod;    
    61     }
    62  cout<<(ans+Mod)%Mod;
    63 } 
  • 相关阅读:
    存储过程,触发器,函数 学习总结
    发布软件之前,怎样告诉用户怎么用
    一种小项目开发结构
    错误记录 两种实现方法
    模具行业生产知识
    请大家警惕这个散播木马的网站 www.zzyqr.com,本文简要地分析了它通过网页的传播方式
    如何保证开发过程中对数据库结构的更新顺利地迁移到产品服务器上。
    三层开发中容易犯的错误
    全局程序集缓存导致cs0006编译错误:找不到元数据文件错误
    for VS. foreach 那个性能更高,为什么,怎么选择
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7285369.html
Copyright © 2011-2022 走看看