[容斥][数论]JZOJ 5810 简单的玄学

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>10^6+3时,分子中必有一个等于模数的因子,即为0

然后约分,分母是2的幂,所以我们求出乘积中的2的次数即可

然后对于0≤a<2n,2n的次数和2n-a的次数相同,所以求出(m-1)!的所有2的次数即可

求m!的2的次数有O(log2(m))的做法,在此不作过多叙述

然后搞一波逆元就行

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const ll P=1e6+3;
ll n,m;

ll Power(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1) ans=ans*x%P;
        x=x*x%P;
        y>>=1;
    }
    return ans;
}

int main() {
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    if ((double)log(m)/log(2)>n) {
        printf("1 1");
        return 0;
    }
    ll fz,fm=Power(Power(2ll,n),m-1ll);
    ll yf=0;
    for (ll i=2ll;i<m;i<<=1ll) yf+=(m-1)/i;
    fm=fm*Power(Power(2ll,yf),P-2ll)%P;
    if (m<=P) {
        ll p=Power(2,n);fz=1;
//        for (ll i=0;i<m;i++) fz=fz*(p+i)%P;
        for (ll i=p-m+1;i<p;i++) fz=fz*i%P;
        fz=fz*Power(Power(2ll,yf),P-2ll)%P;
    }
    else fz=0;
    printf("%lld %lld",((fm-fz)%P+P)%P,fm);
    fclose(stdin);fclose(stdout);
}
View Code

 

posted @ 2018-08-13 21:38  Vagari  阅读(199)  评论(0编辑  收藏  举报