BZOJ3564:[SHOI2014]信号增幅仪 坐标变换+计算几何+最小圆覆盖
BZOJ3884: 上帝与集合的正确用法 数论

BZOJ2219:数论之神 数论

shinbokuow posted @ Feb 27, 2015 01:51:52 PM in BZOJ with tags 数学 , 1644 阅读

思路:

这道题目简直就是数论合集,应用到了好多知识.

我就简单的总结一下吧.

 

这里有一个群\(Z^{*}_{n}\).于是,这东西叫做模\(n\)乘法群.

集合中的元素均小于\(n\)且与\(n\)互质,众所周知集合中应该有\(\phi(n)\)个元素.然后运算就是在模\(n\)意义下的乘法.

根据上述描述很容易发现这东西满足一个群的性质.

然后很显然单位元\(e=1\).

 

接下来介绍生成子群.

对于一个群中的某个元素\(x\),其不断利用群的运算来生成的元素集合,就是关于这个元素的生成子群,记做\(<x>\).

比如对于模\(n\)乘法群而言,\(x\)的生成子群的元素集合就应该是\(\{x,x^2,x^3,...\}\),当然这些都是在模\(n\)意义下的.

我们发现如果有一个最小的正整数\(t\)使得\(x^t=1(mod n)\),那么接下来就会有\(x^{t+1}=x^1,x^{t+2}=x^2,...\),因此我们容易发现:

\[|<x>|=t\]

 

现在我们考虑一个集合中的一个元素\(x\).

我们定义这个元素的\(ord(x)\)表示一个最小的正整数\(t\)使得\(x^t=e=1(mod n)\).显然这个正整数总是存在的.

结合刚才的说明我们得到:

\[|<x>|=ord(x)\]

 

然后如果某个元素\(x'\)使得\(ord(x')=\phi(n)\),我们将\(x'\)叫做\(n\)的原根.

我们不难发现\(<x'>\)和原来群的集合相等.因此\(x',x'^2,x'^3,...x'^{\phi(n)}\)恰好与所有小于\(n\)且与\(n\)互质的正整数一一对应.

以下还是将原根记做\(g\).

 

因此对于每一个群中的元素\(x\),我们令指标\(ind(x)\)表示\(g^{ind(x)}=x(mod n)\),其中\(1\leq{ind(x)}\leq{\phi(n)}\).

这东西显然也是存在的.

 

刚才算是铺垫了一些新知识吧...下面回到我们的题目.

 

题目是要求方程\(x^a=b(mod~p)\)在区间\([0,p-1]\)内的整数解的个数.

首先将\(p\)分解质因数,变成\(p=p_1^{q_1}p_2^{q_2}...\),随后我们依次考虑每一个\(p_i^{q_i}\).

现在方程是\(x^a=b(mod~p_i^{q_i})\),通过中国剩余定理,我们强行YY出最终的答案就是每一个方程的解的数目的乘积.

现在问题就是解这个方程了.

 

一种情况是:\(b=0\),围观标程发现直接返回一个奇怪的东西,目前不知道为什么.

另外一种情况是:\(b\not=1\)且\(gcd(b,p_i^{q_i})=1\),这种就非常科学.因为\(x^a\)以及\(b\)都是在模\(p_i^{q_i}\)乘法群里面的吧.

我们用一种高端方法:对于两边取指标,得到:\(a*ind(x)=ind(b)(mod\phi(p_i^{q_i}))\).

\(ind(b)\)可以用exbsgs搞出来.那么现在问题就变成了解一个线性同余方程,求解的数目.

这个我们有结论:若\(gcd(a,phi(p_i^{q_i}))|ind(b)\),则有\(gcd(a,phi(p_i^{q_i}))\)个解,否则无解.这个我先不证明了.

然后我们就解决了这种情况.

最后一种情况是:\(b\)和\(p_i^{q_i}\)不互质.这时候\(b\)显然是没有指标的.

不妨令\(b=p_i^tb'\),其中\(gcd(b',p_i)=1\).

如果\(t\%a!=0\),显然无解.

否则我们就用\(b'\)代替\(b\)来进行刚才的算法.不过最终的答案还需要乘以一个奇怪的东西.这个目前也不知道为什么.

 

目前好像比较科学的是这个blog:

http://www.cppblog.com/MatoNo1/archive/2013/03/15/198433.html

不过我是没有看懂= =

 

下面是我的代码:(求神犇出现来解决蒟蒻的两个疑问...)

#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef long long LL;
 
inline int ksm(int x,int y){int r=1,t=x;for(;y;y>>=1,t*=t)if(y&1)r*=t;return r;}
inline int ksm(int x,int y,int p){int r=1,t=x;for(;y;y>>=1,t=(LL)t*t%p)if(y&1)r=(LL)r*t%p;return r;}
 
inline 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-=(a/b)*x;}
inline LL solve(LL a,LL b,LL p){
    LL d,x,y;
    if(b%gcd(a,p))return-1;
    exgcd(a,p,d,x,y),x=(x%p+p)%p,x=x*b%p;
    return x;
}
 
inline int proot(int p){
    static int prime[50010];int cnt=0,tmp=p-1;
    for(int i=2;i*i<=tmp;++i){
        if(tmp%i==0){prime[++cnt]=i;while(tmp%i==0)tmp/=i;}
    }if(tmp!=1)prime[++cnt]=tmp;
    for(int i=1;i<p;++i){
        bool ok=1;
        for(int j=1;j<=cnt;++j)if(ksm(i,(p-1)/prime[j],p)==1){ok=0;break;}
        if(ok)return i;
    }
}
 
struct Hashset{
    static const int mod=13131;
    int head[mod],next[300010],f[300010],w[300010],ind;
    inline void clear(){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)return;
        f[ind]=x,w[ind]=v,next[ind]=head[ins],head[ins]=ind++;
    }
    inline int operator[](const int&x){
        int ins=x%mod;
        for(int j=head[ins];j!=-1;j=next[j])if(f[j]==x)return w[j];
        return-1;
    }
}S;
 
inline int bsgs(int c,int a,int b,int p){
    int m=ceil(sqrt(p));
    register int i,j;
    int mi=1;for(S.clear(),i=0;i<m;++i,mi=(LL)mi*a%p)S.insert(mi,i);
    for(i=0;i*m<p;++i){
        j=S[solve((LL)c*ksm(a,i*m,p)%p,b,p)];
        if(j!=-1)return i*m+j;
    }return-1;
}
inline int exbsgs(int a,int b,int p){
    for(int i=0;i<=100;++i)if(ksm(a,i,p)==b)return i;
    int cnt=0,c=1,t;
    while((t=gcd(a,p))>1){
        if(b%t)return-1;
        b/=t,p/=t,c=(LL)c*(a/t)%p,++cnt;
    }
    int re=bsgs(c,a,b,p);
    if(re==-1)return-1;else return re+cnt;
}
 
inline int solve(int a,int b,int p,int t){
    int mi=ksm(p,t),phi=mi-mi/p;b%=mi;
    if(!b)return ksm(p,t-((t-1)/a+1));
    int d=0;while(b%p==0)b/=p,++d;
    if(d%a)return 0;
    int g=proot(p),indb=exbsgs(g,b,mi);
    if(indb==-1||indb%gcd(a,phi))return 0;else return ksm(p,d-d/a)*gcd(a,phi);
}
 
int main(){
    #ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    #endif
     
    int cas;scanf("%d",&cas);
    register int i,j;
    while(cas--){
        int re=1;
        int a,b,k;scanf("%d%d%d",&a,&b,&k),k=k*2+1;
        int tmp=k;
        for(i=2;i*i<=k;++i){
            int t=0;
            if(tmp%i==0){
                while(tmp%i==0)tmp/=i,++t;
                re*=solve(a,b,i,t);
            }
        }if(tmp!=1)re*=solve(a,b,tmp,1);
        printf("%d\n",re);
    }
    return 0;
}

登录 *


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