bzoj2219

8 篇文章 0 订阅

题意:
对于给定的3个非负整数 A,B,K 求出满足 (1) X^A = B(mod 2*K + 1) (2) X 在范围[0, 2K] 内的X的个数
1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<vector>
#define N 100000
#define inf 2e9
#define LL long long
#define hn 7365768
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
int pr[N],pl,ans;
bool b[N];
vector<pii> h[hn+10];
void get_p()
{
    for(int i=2;i<N;i++)
    {
        if(b[i]==0) pr[++pl]=i;
        for(int j=1;j<=pl;j++)
        {
            if(i*pr[j]>=N) break;
            b[i*pr[j]]=1;
            if(i%pr[j]==0) break;
        }
    }
}
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int qmod(int a,int b,LL mmod)
{
    int t=1;
    while(b)
    {
        if(b%2) t=1ll*t*a%mmod;
        b/=2;
        a=1ll*a*a%mmod;
    }
    return t;
}
bool check(int x,int P,int phi)
{
    int q=sqrt(phi);
    for(int i=2;i<=q;i++)
    {
        if(phi%i) continue;
        if(qmod(x,i,P)==1 || qmod(x,phi/i,P)==1) return 0;
    }
    return 1;
}
int findrt(int P,int phi)
{
    for(int i=2;i;i++) if(check(i,P,phi)) return i;
}
int find(int x)
{
    int k=x%hn,siz=h[k].size();
    for(int i=0;i<siz;i++) if(h[k][i].first==x) return h[k][i].second;
    return -1;
}
int get_ind(int x,LL P,int phi)
{
    int g=findrt(P,phi),ny,q=sqrt(phi),res;
    if(q*q<phi) q++;
    ny=qmod(qmod(g,q,P),phi-1,P);
    int t=1;
    for(int i=0;i<q;i++)
    {
        h[t%hn].pb(mp(t,i));
        t=1ll*t*g%P;
    }
    for(int i=0;i<=q;i++)
    {
        int j=find(x);
        if(j!=-1) {res=i*q+j;break;}
        x=1ll*x*ny%P;
    }
    t=1;
    for(int i=0;i<q;i++)
    {
        h[t%hn].clear();
        t=1ll*t*g%P;
    }
    return res;
}
int make(int a,int b,int p,int k)
{
    int P=qmod(p,k,inf),phi=P/p*(p-1);
    a%=phi;
    b=get_ind(b,P,phi);
    int d=gcd(a,phi);
    if(b%d) return 0;
    return d;
}
int cal(int a,int b,int p,int k)
{
    int P=qmod(p,k,inf);
    b%=P;
    if(b==0) {int x=k/a;if(k%a) x++;return qmod(p,k-x,inf);}
    int t=0;
    while(b%p==0) b/=p,t++;
    if(t%a) return 0;
    int s=t/a;
    return make(a,b,p,k-t)*qmod(p,t-s,inf);
}
void solve(int a,int b,int p)
{
    ans=1;
    for(int i=1;i<=pl;i++)
    {
        if(p==1) break;
        if(p%pr[i]) 
        {
            if(pr[i]*pr[i]>p) break;
            continue;
        }
        int k=0;
        while(p%pr[i]==0) k++,p/=pr[i];
        ans=ans*cal(a,b,pr[i],k);
    }
    if(p>1) ans=ans*cal(a,b,p,1);
    printf("%d\n",ans);
}
int main()
{
    get_p();
    int z;scanf("%d",&z);
    while(z--)
    {
        int a,b,p;scanf("%d%d%d",&a,&b,&p);
        p=2*p+1;
        solve(a,b,p);
    }
    return 0;
}

题解:
怎么感觉这题怪怪的
设p=2k+1
首先要知道可以p分解成 pkii ,把每个 pkii 当模数的解数乘起来就是答案。因为每条方程都是 x=ri(%ai) 的形式,每组解就是不同的ri。每种ri的选法拿去crt都可以得到唯一的不同的解。
对于每个 pk
如果 b=0(%pk) 是简单的
否则注意 pk 是有原根的,如果b和p互质找出 gl=b ,设 gr=x 就随便做了。。
如果不互质就有点奇怪。。
b=bpt
显然此时t要是a的倍数
s=tax=xps
现在就是要找出 x[0,pks] 满足 xa=b(%pk)
原方程是 xapt=bpt(%pk) ,用心感受一下就知道 x[0,pkt] 的解就是 xa=b(%pkt) 的解
发现每个解加若干倍的 pkt 代回原方程也是资磁的。。
于是每个解就变成了 pts 个解了。。
然后就做完了。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值