[NOIP2017模拟]Math

2017.10.24 T3 2009

样例数据
输入

2
2 3
2 2

输出

3
2

分析:这是一道数论题
1、当a为奇数时,b一定为奇数。
ab(mod2) a21(mod4),b21(mod4)aba(mod4),bab(mod4)ab(mod4)
这是因为b=2x+1所以说a前面的2x次方都模成了1,即 a1ab(mod4) ,b同理。
以此类推, ab(mod4) a21(mod8),b21(mod8)aba(mod8),bab(mod8)ab(mod8)
ab(mod8) a41(mod16),b41(mod16)aba(mod16),bab(mod16)ab(mod16)...
可以得到 ab(mod2n) ,又1<=b<= 2n 所以b只有唯一解。
2、当a为偶数时,b一定为偶数。
b>=n时,则 ab0(mod2n) ,故 ba0(mod2n) ,可以直接求出b>=n时的个数。 ba % 2n =0,设b= 2kc (2kc)a=2kaca 即k*a>=n,k>= an ,所以b要是 2an 的倍数就可以了。
b < <script type="math/tex" id="MathJax-Element-18"><</script>n,则直接暴力。
时间复杂度O( Nloga )。
如果打表也是可以找到奇数的情况的规律的,偶数就看造化了。
明明给了30%的档让我们直接枚举、快速幂、判断,但是都没有人能拿满……卡常数卡得也是没谁了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

int T,a,n,ans;
int mi[35];

long long ksm(long long x,long long y)
{
    long long res=1;
    for(;y>=1;x=x*x%mi[n],y=(y>>1))
        if(y&1)
            res=res*x%mi[n];
    return res;
}

int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);

    mi[0]=1;
    for(int i=1;i<=30;++i)
        mi[i]=mi[i-1]*2;

    T=getint();
    while(T--)
    {
        ans=0;
        a=getint(),n=getint();
        if(a%2==1)//奇数
            cout<<1<<'\n';
        else//偶数
        {
            long long x,y;
            for(int i=2;i<=n;i+=2)//n以内直接暴力快速幂
            {
                x=ksm(a,i);
                y=ksm(i,a);
                if(x==y)
                    ans++;
            }

            if(n%a==0)//大于n(为什么要if、else?这只是是向上取整操作写得丑而已)
            {
                ans+=mi[n]/mi[n/a];//1<=b<=2^n,所以在这个范围内找2^(n/a)的倍数
                ans-=n/mi[n/a];//前提是b>=n,所以在n以内的要去掉
            }
            else
            {
                ans+=mi[n]/mi[n/a+1];
                ans-=n/mi[n/a+1];
            }
            cout<<ans<<'\n';
        }
    }
    return 0;
}

本题结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值