[NOIP模拟][数学推理]Math

题目描述:
题目大意:
给定a,n(a≤ 109 ,n≤30),求有多少b(1≤b≤ 2n )满足: abba(mod2n) 。多组数据。
样例输入

2
2 3
2 2

样例输出

3
2

题目分析
找规律加数学推理。首先分两种情况:
a为奇数:如果你打了个暴力,然后打打表什么的就可以发现答案恒为1。证明如下:
1、a为奇数,b也一定为奇数,否则, ab ba 的奇偶性不同,就不可能同余 2n
2、再证明 ba(mod2n) ,利用数学归纳。
       ①奇数平方模8余1(你可以写成 2n+12 展开就能证明),所以有 aba(mod8) , 证明 ab8 a2ka18 (假设b=2k+1) (ak)2a8 1*a%8,即 aba(mod8) ,同理 bab(mod8) ,又因为题目中要求的是 abba(mod2n) ,那么可得 abba(mod8) (此步证明见最后),于是再综合前面两个得 ab(mod8)
       ②奇数四次方模16余1,所以有 abab4(mod16) , 证明 ab16 a4k ab416 (令b=4k+b%4) (ak)4ab416 1ab416 ,即 abab4(mod16) ,同理 baba4(mod16) ,又因为题目中要求的是 abba(mod2n) ,那么可得 abba(mod16) ,那么综合前面的可得 ab4ba4(mod16) ,又因为 abba(mod2n) ,那么可得 abba(mod4) ,于是得 ab(mod4) ,即a%4=b%4,所以得到 ab(mod16)
        ③同理我们可得 ab(mod32)
3、于是归纳得出满足要求的a,b满足条件 ba(mod2n) ,又因为a,n确定,且1≤b≤ 2n ,那么b就是唯一确定,即答案为1。
a为偶数:
1、同理b也一定为偶数。
2、若n≤b,则 ab0(mod2n) ,因为题目要求 abba(mod2n) ,故 ba0(mod2n) 。再设b= 2kc (2kc)a2kaca0(mod2n) ,于是得n≤a*k na ≤k(向上取整),即 2na 整除 2k 2na 整除b,因为1≤b≤ 2n ,所以n≤b的范围内,符合要求的b个数就是看 2n 内有多少个 2na 的倍数,即 2n / 2na (如果 2na 小于n,还需减去n以内 2na 的倍数的个数,即n/ 2na )。
3、若 b<n ,因为n≤30,暴力枚举加判断就行。
PS: 证明 abba(mod2n) 可推得 abba(mod2k) k<n ), abba(mod2n) ab=ba+2nx ab=ba+2km abba(mod2k)
附代码

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

int mi[50],t,n,a,ans,x;

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

int ksm(int  x,int y)
{
    int ret=1;
    for(;y;y/=2,x=(long long)(x*x)%mi[n])
        if(y&1) ret=(long long)(ret*x)%mi[n];
    return ret;
}

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

    mi[0]=1;
    for(int i=1;i<=30;i++)//预处理2的次幂
        mi[i]=(mi[i-1]<<1);
    t=readint();
    while(t--)
    {
        a=readint();n=readint();
        if(a%2==1) printf("1\n");
        else
        {
            ans=0;
            x=(n+a-1)/a;//相当于向上取整
            ans+=mi[n]/mi[x];
            ans-=n/mi[x];
            for(int i=2;i<=n;i+=2)
                if(ksm(a,i)==ksm(i,a)) ans++;
            printf("%d\n",ans);
        }
    }

    return 0;
}
发布了99 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qianguch/article/details/78331879
今日推荐