阿里云秘钥池

对于每个正整数 nn,我们定义它的 pp 进制表示 由 mm 个非负整数 a_1, a_2, cdots, a_ma1​​,a2​​,,am​​ 组成,并且这些数字满足 displaystyle n = sum_{i = 1}^{m}{a_i p^{i - 1}}n=i=1m​​ai​​pi1​​,以及 0 leq a_i < p (i = 1, 2, cdots, m - 1)0ai​​<p (i=1,2,,m1) 和 1 leq a_m < p1am​​<p。

在阿里云台上,用户登录的秘钥都是由一个正整数组成。一个可被用作秘钥的正整数 nn,它的 pp 进制表示需要满足 1 leq a_i < p (i = 1, 2, cdots, m)1ai​​<p (i=1,2,,m) 且 gcd(a_i, a_{i + 1}) = 1 (i = 1, 2, cdots, m - 1)gcd(ai​​,ai+1​​)=1 (i=1,2,,m1)。比如当 p = 10p=10 时,6161 是一个合法秘钥,32163216 也是;但是当 p = 100p=100 时,6161 依旧是一个合法秘钥,32163216 却不是。

给出正整数 L, RL,R 和 pp,请你统计满足 L leq n leq RLnR 并且 nn 是一个合法秘钥的正整数 nn 的数量。

输入格式

第一行包含一个正整数 T(1 leq T leq 10^3)T(1T103​​),表示有 TT 组测试数据。

接下来依次给出每组测试数据,每组测试数据仅一行,包含三个正整数 L, R(1 leq L leq R leq 10^{18})L,R(1LR1018​​) 和 p(2 leq p leq 10^5)p(2p105​​) ,含义见题目描述。

保证不超过 5050 组数据满足 p > 10^3p>103​​。

输出格式

对于每组数据输出一行,包含一个整数,表示满足条件的数字数量。

样例输入

4
5 7 9
1 100 2
1 100 5
2017 2121 10

样例输出

3
6
41
10
分析:考虑第一次最高位比原数小的,后面的信息可以直接用莫比乌斯得到;
   这样依次按位枚举即可;
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=(int)n;i++)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
#define ls rt<<1
#define rs rt<<1|1
#define all(x) x.begin(),x.end()
const int maxn=1e5+10;
const int N=2e2+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%mod;p=p*p%mod;q>>=1;}return f;}
int n,m,k,t,p[maxn],mo[maxn],phi[maxn],cnt,num[20];
bool vis[maxn];
vector<ll>ret[maxn],sum[maxn];
void init()
{
    mo[1]=1;
    phi[1]=1;
    for(int i=2;i<=maxn-10;i++)
    {
        if(!vis[i])
        {
            mo[i]=-1;
            phi[i]=i-1;
            p[cnt++]=i;
        }
        for(int j=0;j<cnt&&(ll)i*p[j]<=maxn-10;j++)
        {
            vis[i*p[j]]=true;
            if(i%p[j]==0)
            {
                mo[i*p[j]]=0;
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            mo[i*p[j]]=-mo[i];
            phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
}
void build(int len,int bs)
{
    int i,j,k;
    rep(i,0,len)ret[i].resize(bs),sum[i].resize(bs);
    rep(i,1,bs-1)ret[1][i]=1,sum[1][i]=0;
    rep(i,1,bs-1)
    {
        for(j=i;j<bs;j+=i)sum[1][i]+=ret[1][j];
    }
    rep(i,2,len)
    {
        for(j=1;j<bs;j++)ret[i][j]=0,sum[i][j]=0;
        for(j=1;j<bs;j++)
        {
            for(k=j;k<bs;k+=j)
            {
                ret[i][k]+=mo[j]*sum[i-1][j];
            }
        }
        for(j=1;j<bs;j++)
        {
            for(k=j;k<bs;k+=j)
            {
                sum[i][j]+=ret[i][k];
            }
        }
    }
}
ll gao(ll x,int bs,int tp)
{
    int pos=0;
    while(x)num[++pos]=x%bs,x/=bs;
    if(tp)build(pos,bs);
    ll ans=0;
    int i,j;
    rep(i,1,pos-1)rep(j,1,bs-1)ans+=ret[i][j];
    for(i=pos;i>=1;i--)
    {
        for(j=1;j<num[i];j++)
        {
            if(i==pos||__gcd(num[i+1],j)==1)ans+=ret[i][j];
        }
        if(num[i]==0||(i!=pos&&__gcd(num[i],num[i+1])!=1))break;
    }
    return ans;
}
int main()
{
    int i,j;
    init();
    scanf("%d",&t);
    while(t--)
    {
        ll p,q;
        scanf("%lld%lld%d",&p,&q,&m);
        printf("%lld
",gao(q+1,m,1)-gao(p,m,0));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/dyzll/p/7356617.html