1. 程式人生 > >刷題總結——math(NOIP模擬)

刷題總結——math(NOIP模擬)

情況 math temp for names namespace ios 個數 std

題目:

給定兩個數字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; }

刷題總結——math(NOIP模擬)