码迷,mamicode.com
首页 > 其他好文 > 详细

【[CQOI2015]选数】

时间:2019-01-01 21:09:51      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:map   相等   using   就会   分块   最大   register   math   names   

这道题自然是可以反演的

按照反演的套路我们先设出两个函数

\(F(n)\)表示从\([L,H]\)中任选\(N\)个数的最大公约数是\(n\)或者\(n\)的倍数的情况数

\(f(n)\)表示从\([L,H]\)中任选\(N\)个数的最大公约数是\(n\)的情况数

非常显然的是

\[F(n)=\sum_{n|d}f(d)\]

\[f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)\]

开始反演了

首先我们发现我们求\(f(k)\)并不好求,因为没有办法整除分块

所一我们把\(L/k,H/k\)之后求\(f(1)\)就好了

吗?

显然并不行啊

我们考虑一下如果\(L\%k!=0\)\(\left \lfloor \frac{L}{k} \right \rfloor\times k<L\),就会使一些不在\([L,H]\)内的数混进答案里了

所以如果\(L\%k!=0\)的话,除以\(k\)之后再将\(L+1\)

之后就是如何表示\(F\)

非常显然就是

\[F(n)=(\left \lfloor \frac{H}{n}\right \rfloor-\left \lfloor \frac{L-1}{n}\right \rfloor)^N\]

\[f(1)=\sum_{i=1}\mu(i)F(i)\]

\(F(i)\)相等的用整除分块处理

但是这道题的\(H\)非常大,甚至都不能线筛

不能线筛杜教筛总可以了吧,于是就可以用\(O(H^{\frac{2}{3}})\)的复杂度解决这道题

#include<iostream>
#include<cstring>
#include<cstdio>
#include<tr1/unordered_map>
#define re register
#define maxn 5000001
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int mod=1000000007;
using namespace std::tr1;
unordered_map<int,int> ma;
int p[maxn>>1],f[maxn],mu[maxn];
inline LL quick(int a,int b)
{
    LL S=1;
    while(b) {if(b&1) S=S*a%mod;b>>=1;a=(LL)a*(LL)a%mod;}
    return S;
}
int N,K,L,H,M;
int solve(int x)
{
    if(x<=M) return mu[x];
    if(ma.find(x)!=ma.end()) return ma[x];
    int ans=1;
    for(re int l=2,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ans-=solve(x/l)*(r-l+1);
    }
    return ma[x]=ans;
}
int main()
{
    scanf("%d%d%d%d",&N,&K,&L,&H);
    H/=K;
    if(L%K==0) L=L/K;
        else L=L/K+1;
    M=min(H,5000000);
    mu[1]=f[1]=1;
    for(re int i=2;i<=M;i++)
    {
        if(!f[i]) p[++p[0]]=i,mu[i]=-1;
        for(re int j=1;j<=p[0]&&p[j]*i<=M;j++)
        {
            f[p[j]*i]=1;
            if(i%p[j]==0) break;
            mu[i*p[j]]=-1*mu[i];
        }
    }
    for(re int i=1;i<=M;i++) mu[i]+=mu[i-1];
    LL ans=0;L--;
    for(re int l=1,r;l<=H;l=r+1)
    {
        if(!(L/l)) r=H/(H/l);
            else r=min(H/(H/l),L/(L/l));
        ans=(ans+quick(H/l-L/l,N)*(LL)(solve(r)-solve(l-1))%mod)%mod;
    }
    printf("%lld\n",((ans%mod)+mod)%mod);
    return 0;
}

【[CQOI2015]选数】

标签:map   相等   using   就会   分块   最大   register   math   names   

原文地址:https://www.cnblogs.com/asuldb/p/10205657.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!