[ksm][数学] Jzoj P5810 简单的玄学

Description

 

Input

第一行两个正整数 n, m。 

Output

一行两个整数,它们的含义如题所述。 
 

Sample Input

【样例 1 输入】
3 2

【样例 2 输入】
1 3

【样例 3 输入】
4 3
 

Sample Output

【样例 1 输出】 
1 8 
【样例 2 输出】 
1 1 
【样例 3 输出】 
23 128
 

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。

 

题解

  • 可以考虑将问题转换为求m个数都互不相同的概率
  • 显然,对于所有人取数的可能性是2^nm
  • 那么现在如果确定了1号的数,那么2与它不相同的概率求出2^n-1,3与1、2不相同的概率就是2^n-2...以此类推
  • 一共有m-1个数
  • 那么总共就是
  • 然后考虑将其约分,那么对于分母是只有2的质因数的,那么分子也只能约2
  • 考虑能约多少个
  • 对于任意一个1<=a<2^n,a与2^n-a的中2的次数相同
  • 因此,只用求出(m-1)!的2的次数就好了
  • 答案就是1-a/b=(b-a)/b

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 const long long mo=1e6+3;
 7 long long n,m;
 8 long long ksm(long long a,long long b)
 9 {
10     long long r=1;
11     for(;b;b>>=1,a=a*a%mo) if(b&1) r=r*a%mo;
12     return r;   
13 }
14 int main()
15 {
16     scanf("%lld%lld",&n,&m);
17     if (log2(m)>n) 
18     {
19         printf("1 1\n");
20         return 0;
21     }
22     long long a=ksm(2,n),down=ksm(a,m),up=1;
23     for (long long i=0;i<m;i++)
24     {
25         up=up*(a-i)%mo;
26         if (!up) break;
27     }
28     m--; long long k=n;
29     for (long long i=2;i<=m;i<<=1) k+=m/i;
30     down=down*ksm(500002,k)%mo;
31     up=up*ksm(500002,k)%mo;
32     printf("%lld %lld\n",(down-up+mo)%mo,down);
33 }

 

posted @ 2018-08-13 21:03  BEYang_Z  阅读(311)  评论(0编辑  收藏  举报