[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< 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;
}

本題結。

發佈了152 篇原創文章 · 獲贊 136 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章