zoukankan      html  css  js  c++  java
  • [SDOI2011]计算器(BSGS)

    洛古题面

    对于操作一,用快速幂算即可

    代码如下

    int quickpow(int a,int b,int k)
    {
        int r=1;
        while(b)
        {
            if(b&1) r=(r*a)%k;
            b>>=1;
            a=(a*a)%k;
        }
        return r;
    }
    

    对于操作二,用拓展欧几里得算法即可。
    已知(a,b,n),求(x)的最小值,使得(a*x≡b(mod p)),可以转化为:(a*x+p*y=b),则要求(gcd(a,n)|b),否则无解。不定方程的求法可以参照这道题

    (exgcd)代码如下

    int exgcd(int a,int b,int&x,int&y)
    {
        if(!b)
        {
            x=1,y=0;
            return a;
        }
        re int gcd=exgcd(b,a%b,y,x);
        y-=(a/b)*x;
        return gcd;
    }
    

    对于操作三,我们需要用到一个新的算法B(拔)S(山)G(盖)S(世),他可以快速的求出求,满足(a^x ≡ b(mod p))的最小的非负整数(x)

    求法是将(x)拆分成(i*m-j)的形式(其中(m)(sqrt(p))向上取整的值,则原式化为(a^{i*m-j} ≡ b(mod p))

    移向后得(a^{i*m} ≡ b*a^j(mod p))

    我们从(0-m)枚举(j),并将(b*a^j)的所有值存入哈希表中

    接着在从(1-m)枚举(i),算出所有的(a^{i*m})

    如果一个i对应的(a^{i*m})的值已经在哈希表中,则表明i*m-j为一个解,输出此时的解即可

    因为j<=m,所以求出的解随i的增大而减小,所以最先求出的i所对的解,即为所求。

    	re int y=read(),z=read(),p=read();
    	re int m=ceil(sqrt(p));
    	if(y%p==0&&z)
    	{
    		puts("Orz, I cannot find x!");
    		continue;
    	}
        //这里要特判,因为如果y%p==0了,那么不管x取何值,(y^x)%p一定为0。
    	a.clear();
    	re int now=z%p,f=quickpow(y,m,p);
    	a[now]=0;
    	for(re int i=1;i<=m;++i)
    	{
    		now=(now*y)%p;
    		a[now]=i;
    	}
    	now=1;
    	re int flag=1;
    	for(re int i=1;i<=m;++i)
    	{
    		now=(now*f)%p;
    		if(a[now])
    		{
    			re int ans=(i*m-a[now])%p;
    			printf("%lld
    ",(ans+p)%p);
    			flag=0;
    			break;
    		}
    	}
    	if(flag) puts("Orz, I cannot find x!");
    

    所有代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define il inline
    #define re register
    #define debug printf("Now is Line : %d
    ",__LINE__)
    #define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
    #define int long long
    map<int,int>a;
    il int read()
    {
        re int x=0,f=1;re char c=getchar();
        while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return x*f;
    }
    il int quickpow(int a,int b,int k)
    {
        re int r=1;
        while(b)
        {
            if(b&1) r=(r*a)%k;
            b>>=1;
            a=(a*a)%k;
        }
        return r;
    }
    il int exgcd(int a,int b,int&x,int&y)
    {
        if(!b)
        {
            x=1,y=0;
            return a;
        }
        re int gcd=exgcd(b,a%b,y,x);
        y-=(a/b)*x;
        return gcd;
    }
    signed main()
    {
        re int T=read(),k=read();
        if(k==1)
        {
            while(T--)
            {
                re int y=read(),z=read(),p=read();
                printf("%lld
    ",quickpow(y,z,p));
            }
        }
        else if(k==2)
        {
            while(T--)
            {
                re int a=read(),b=read(),p=read(),x,y;
                re int gcd=exgcd(a,p,x,y);
                if(b%gcd) puts("Orz, I cannot find x!");
                else
                {
                    re int temp=p/gcd;
                    while(x<0) x+=temp;
                    printf("%lld
    ",((x*b/gcd)%temp+temp)%temp);
                }
            }
        }
        else
        {
            while(T--)
            {
                re int y=read(),z=read(),p=read();
                re int m=ceil(sqrt(p));
                if(y%p==0&&z)
                {
                    puts("Orz, I cannot find x!");
                    continue;
                }
                a.clear();
                re int now=z%p,f=quickpow(y,m,p);
                a[now]=0;
                for(re int i=1;i<=m;++i)
                {
                    now=(now*y)%p;
                    a[now]=i;
                }
                now=1;
                re int flag=1;
                for(re int i=1;i<=m;++i)
                {
                    now=(now*f)%p;
                    if(a[now])
                    {
                        re int ans=(i*m-a[now])%p;
                        printf("%lld
    ",(ans+p)%p);
                        flag=0;
                        break;
                    }
                }
                if(flag) puts("Orz, I cannot find x!");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    【 socke】C# socket端口复用-多主机头绑定
    【网络】 NAT
    【socket】高级用法-ReceiveMessageFrom
    【socket】高级用法-异步
    C# GET 和 SET作用
    多态是什么意思?
    LINQ(LINQ to Entities)
    LINQ(隐式表达式、lambda 表达式)
    LINQ(LINQ to DataSet)
    C# 中的委托和事件
  • 原文地址:https://www.cnblogs.com/bcoier/p/10293061.html
Copyright © 2011-2022 走看看