这题真挺不错的,需要一些数学知识,对细节要求高。
一些资料与参考:
寻找一共有多少个2的因子时用的方法不错。
不能写成pow,要写成mypow。
最后输出分子时要多次取模防止出现负数。
当a为正整数,m为素数,而且a与m互素时,a模m的逆元为a^(m-2)模m。
此题中a为2,m为一个素数。显然2与m互素。代入公式直接求逆元。
求逆元是为了使用除法逆元公式。
( a/b ) % c == ( a*b1 ) % c==((a%c)*(b1%c))%c
其中b1是b模c的逆元。
在计算过程中需要求分子分母gcd模m的逆元。
带入公式,即2^(cnt*(m-2))%m的值。
难道直接mypow(mypow(2,cnt),m-2)%m来算吗?
其实完全可以这样算,几乎不会更慢。但这个表达式是可以化简的。
根据费马小定理,2^(m-1)%m==1。
所以:2^(cnt*(m-2))%m=(2^(m-1)%m * 2^(m-1)%m * ...... * 2^(m-1)%m * 2^(cnt*(m-2)%(m-1)))%m=2^(cnt*(m-2)%(m-1))%m。
乘法取模,化简,乘开来,化简,得:2^(-cnt%(m-1))%m,。
根据费马小定理,以及乘法取模上式=(2^(-cnt%(m-1))*2^(m-1))%m=2^(m-1-tmp%(m-1))。
这就是代码中aaa的由来。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000003;
ll n,k;
ll mypow(ll x,ll n)
{
ll ret=1;
while(n)
{
if(n&1)
{
ret=(ret*x)%mod;
}
x=(x*x)%mod;
n>>=1;
}
return ret;
}
int main()
{
scanf("%I64d %I64d",&n,&k);
ll x=0;
while((1ll<<x)<k) x++;
if(x>n)
{
puts("1 1");
return 0;
}
ll cnt=0;
for(ll i=2;i<k;i<<=1)
{
cnt+=(k-1)/i;//这个方法好,一开始在这里超时了。我还一个个的找。
}
ll aaa=mypow(2,mod-1-cnt%(mod-1));//用mypow不能用pow,aaa化简了,但并没有快多少。
ll fm=(mypow(mypow(2,n),k-1)*aaa)%mod;
if(k-1>=mod) printf("%I64d %I64d\n",fm,fm);
else
{
ll fz=1;
ll da=mypow(2,n);
for(ll i=1;i<k;i++)
fz=(fz*(da-i))%mod;
fz=(fz*aaa)%mod;
printf("%I64d %I64d\n",((fm-fz)%mod+mod)%mod,fm);//小细节,为了防止输出负数。
}
return 0;
}