刷题总结——math(NOIP模拟)

题目:

  给定两个数字n,求有多少个数字b满足a^b和b^a同余于2^n,其中n<=30,a<=10^9,

题解:

  挺巧妙的一道题···从中深深体会到打表的重要性···

  首先根据ab奇偶性分情况讨论···若ab奇偶性不同的话肯定不会满足条件···因此要么ab同时为奇数··要么同时为偶数··

  若ab同时为奇数··根据打表(证明考试时我是想不到的···)可得只有当ab相等时条件才成立··

  若ab同时为偶数···当b<=n时可以直接暴力求··当b>n时,可以解得a^b肯定是可以被2^n整除的··因此我们要求b^a可以被2^n整除的个数··我们设b=2^k*c,其中c为奇数··可得b^a=2^(k*a)*(c^a),因此可以得出2^(k*a)>=2^n,推出k>=n/a,因此我们可以推出2^(n/a)肯定是整除b的··因此我们只需要找出在n到2^n的范围中有多少个数可以被2^(n/a)整除即可··注意这里的除法是向上取整

代码:

  

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
long long Bit[35],mod,T,n,a;
inline long long ksm(long long a,long long b)
{
  long long ans=1;
  while(b)
  {
    if(b%2==1)  ans=ans*a%mod;
    b/=2;a=a*a%mod;
  }
  return ans;
}
inline void pre()
{
  Bit[0]=1;
  for(int i=1;i<=30;i++)  Bit[i]=Bit[i-1]*2;
}
inline long long R()
{
  char c;long long f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=f*10+c-'0';
  return f;
}
int main()
{
  //freopen("math.in","r",stdin);
  // freopen("math.out","w",stdout);
  pre();T=R();
  while(T--)
  {
    a=R();n=R();int ans=0;mod=Bit[n];
    if(a%2==1)
    {
      cout<<"1"<<endl;
      continue;
    }
    else
    {
      for(int i=1;i<=n;i++)
        if(ksm(a,i)==ksm(i,a))  ans++;
      int temp=(n+a-1)/a;
      int up=Bit[n]/Bit[temp];
      int down=n/Bit[temp];ans+=up-down;
      cout<<ans<<endl;
    }
  }
  return 0;
}

 

posted @ 2017-10-24 16:19  AseanA  阅读(163)  评论(0编辑  收藏  举报