Data Constraint
对于 10% 的数据,nm < 16;
对于 30% 的数据,nm < 64;
对于 50% 的数据,nm ≤ 10^3;
对于 70% 的数据,m ≤ 10^6;
对于 100% 的数据,1 ≤ n ≤ 10^18 , 2 ≤ m ≤ 10^18
题解
要求至少有两个相同的,的确不好求。
正难则反,求完全不同的方案数,然后用1减。
那么,完全不同的方案数
考虑约分,先给出一个结论,X!里面有因子2的个数是X-X在二进制中1的个数。
和
前面一个数在二进制中1的个数很好求,
关键是
,很显然,开头一段都是1,然后从m的第一位带m的最后一个1 之前,都是跟m去反,m的最后一个1对于的那一位就是1,最后的都是0。
这个很好理解。
约分之后,就可以直接O(m)地乘,如果m大于模数,最后取模之后就是0了。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
const int mo=1000003;
ll ksm(ll x,ll y)
{
ll s=1;x=x%mo;
for(;y;x=x*x%mo,y>>=1)
if(y&1)s=s*x%mo;
return s;
}
ll n,m,ss,s,nn,mm,p,t,ny,ans,sm;
int main()
{
freopen("random.in","r",stdin);
freopen("random.out","w",stdout);
scanf("%lld%lld",&n,&m);
s=1;p=mo-1;nn=n%p;mm=m%p;
for(int i=1;i<=n;i++)
{
s=s<<1;
if(s>m)break;
}
if(s<m)
{
printf("1 1\n");
return 0;
}
for(s=m,sm=ss=0;s;s>>=1)
{
if(ss==0)
{
if(s&1)ss=1;
}
else ss=ss+!(s&1);
sm++;
}
ss=n-sm+ss;
t=m+ss-1;t=t%p;
s=ksm(2,(nn*mm%p-t+p)%p);
if(m>=mo)
{
printf("%lld %lld\n",s,s);
return 0;
}
ans=1;ss=ksm(2,nn)-m+1;
ss=(ss+mo)%mo;
for(int i=1;i<=m;i++)
ans=ans*ss%mo,ss++;
ny=ksm(2,p-1);
ans=ans*ksm(ny,t)%mo;
ans=(s-ans+mo)%mo;
printf("%lld %lld",ans,s);
return 0;
}