Processing math: 0%
BZOJ2480: Spoj3105 Mod
BZOJ2708: [Violet 1]木偶 贪心+dp

再观BZOJ2219数论之神...

shinbokuow posted @ 10 年前 in BZOJ with tags 数论 数学 BSGS 原根 EXBSGS , 1987 阅读

 

题解:

当时A掉的时候其实并不会...

于是现在膜别人的题解终于会啦!

求方程x^a\equiv{b}\pmod{n}[0,n-1]内的解的个数.
我们考虑通过对于两边取指标,转化为线性同余方程问题.
但是发现n不一定存在原根,我们将n进行质因数分解.
原方程的解的个数等于每一个子方程x^a\equiv{b}\pmod{p_i^{q_i}}解的个数的乘积.
我们考虑中国剩余定理,就能发现这样的乘法原理显然成立.
于是我们只考虑每一个子方程的解的个数.
我们考虑以下几种情况:
(1)b存在指标,即(b,p_i)=1
我们对两边取指标得到a\times{ind(x)}\equiv{ind(b)}\pmod{\phi(p_i^{q_i})}
由线性同余方程的知识可知,如果(a,\phi(p_i^{q_i}))\not|ind(b),则无解;
否则解的个数为(a,\phi(p_i^{q_i})).
(2)b不存在指标,且b=0
我们可以得到p_i|x,不妨令x=cp_i^{x'}((c,p_i)=1),可以得到ax'\geq{q_i},即x'\geq{\lceil\frac{q_i}{a}\rceil}.
所以我们有只需满足p_i^{\lceil\frac{q_i}{a}\rceil}|x,于是解的个数就为p_i^{q_i-\lceil\frac{q_i}{a}\rceil}.
(3)b不存在指标,且b\not=0
不妨令b=cp_i^{b'}((c,p_i)=1).
b'\%a\not=0,显然无解.
否则我们将等式两边同除p_i^{b'}得到:
(\frac{x}{p_i^{\frac{b'}{a}}})^a\equiv{c}\pmod{p_i^{q_i-b'}}
x'=\frac{x}{p_i^{\frac{b'}{a}}},由于满足(2)的条件,我们可以求出x'的解的个数.
注意x'的范围是[0,p_i^{q_i-b'}),但原式的\frac{x}{p_i^{\frac{b'}{a}}}范围是[0,p_i^{q_i-\frac{b'}{a}}).
这相当于我们求出的解是在每个长度为p_i^{q_i-b'}的区间中的解的个数.
所以我们需要将解的个数乘以p^{b'-\frac{b'}{a}}.
于是我们就彻底解决了这个问题!
 
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include<cmath>
#include<cstdio>
#include<cctype>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
  
typedef long long ll;
  
ll pow(ll x,ll y,ll p){
    ll re=1,t=x;
    for(;y;y>>=1,t=t*t%p)
        if(y&1)
            re=re*t%p;
    return re;
}
ll pow(ll x,ll y){
    ll re=1,t=x;
    for(;y;y>>=1,t*=t)
        if(y&1)
            re*=t;
    return re;
}
  
ll gcd(ll a,ll b){
    return(!b)?a:gcd(b,a%b);
}
  
inline void exgcd(ll a,ll b,ll&d,ll&x,ll&y){
    if(!b){
        d=a;
        x=1;
        y=0;
    }
    else{
        exgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
inline ll inv(ll a,ll n){
    ll d,x,y;
    exgcd(a,n,d,x,y);
    return(x%n+n)%n;
}
  
inline ll get_g(ll p){
    static int pr[110];
    int top=0;
    ll t=p-1;
    for(int i=2;i*i<=p-1;++i){
        if(t%i==0){
            pr[++top]=i;
            while(t%i==0)
                t/=i;
        }
    }
    if(t!=1)
        pr[++top]=t;
    for(int i=1;;++i){
        bool ok=1;
        for(int j=1;j<=top;++j)
            if(pow(i,(p-1)/pr[j],p)==1){
                ok=0;
                break;
            }
        if(ok)
            return i;
    }
}
  
struct Hashset{
    static const int mod=13131;
    int head[mod],next[30010],f[30010],v[30010],ind;
    inline void reset(){
        ind=0;
        memset(head,-1,sizeof head);
    }
    inline void insert(int x,int _v){
        int ins=x%mod;
        for(int j=head[ins];j!=-1;j=next[j])
            if(f[j]==x){
                v[j]=min(v[j],_v);
                return;
            }
        f[ind]=x;
        v[ind]=_v;
        next[ind]=head[ins];
        head[ins]=ind++;
    }
    inline int operator[](int x){
        int ins=x%mod;
        for(int j=head[ins];j!=-1;j=next[j])
            if(f[j]==x)
                return v[j];
        return -1;
    }
}M;
  
ll BSGS(ll c,ll a,ll b,ll p){
    ll m=ceil(sqrt(p)),t=1,ct=c;
    M.reset();
    for(int i=0;i<m;++i,(t*=a)%=p,(ct*=a)%=p)
        M.insert(ct,i);
    t=inv(t,p);
    for(int i=0;i*m<p;++i,(b*=t)%=p)
        if(M[b]!=-1)
            return i*m+M[b];
    return -1;
}
ll EXBSGS(ll a,ll b,ll p){
    ll c=1,tim=0,_gcd;
    while((_gcd=gcd(a,p))!=1){
        if(b%_gcd)
            return -1;
        p/=_gcd;
        ++tim;
        (c*=(a/_gcd))%=p;
        (b/=_gcd)%=p;
    }
    ll ans=BSGS(c,a,b,p);
    if(ans!=-1)
        ans+=tim;
    return ans;
}
  
ll solve(ll a,ll b,ll p,ll t){
    b%=pow(p,t);
    if(b==0)
        return pow(p,t-((t-1)/a+1));
    int _b=0;
    while(b%p==0)
        b/=p,++_b;
    ll phi=pow(p,t)*(p-1)/p;
    ll g=get_g(p);
    if(_b==0){
        ll ind_b=EXBSGS(g,b,pow(p,t));
        if(ind_b%gcd(a,phi))
            return 0;
        return gcd(a,phi);
    }
    else{
        if(_b%a)
            return 0;
        else
            return solve(a,b,p,t-_b)*pow(p,_b-_b/a);
    }
}
  
int main(){
#ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
#endif
    int T;
    cin>>T;
    ll A,B,K,n,_n;
    int cnt;
    while(T--){
        scanf("%lld%lld%lld",&A,&B,&K);
        n=_n=K<<1^1;
        ll ans=1;
        for(int i=2;i*i<=n;++i){
            if(_n%i==0){
                cnt=0;
                while(_n%i==0)
                    ++cnt,_n/=i;
                ans*=solve(A,B,i,cnt);
            }
        }
        if(_n!=1)
            ans*=solve(A,B,_n,1);
        printf("%lld\n",ans);
    }
    return 0;
}

 

ww140142 说:
10 年前

看个博客还有注册个号差评。。

Avatar_small
wyfcyx 说:
10 年前

@ww140142: 那是为了要评论没办法啊。。。

ww140142 说:
10 年前

并不是这个意思,我是说那个网址进去要在OJ注册账号= =

Avatar_small
wyfcyx 说:
10 年前

@ww140142: 好吧0.0


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter