• bzoj3209: 花神的数论题


    Description

    背景
    众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
    描述
    话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
    花神的题目是这样的
    设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。

    Input

    一个正整数 N。

    Output

    一个数,答案模 10000007 的值。

    Sample Input

    3
    

    Sample Output

    2
    

    HINT

    对于样例一,1*1*2=2;

    数据范围与约定

    对于 100% 的数据,N≤10^15

    题解

    假设二进制中有(i)个1的数的个数为(s[i]),那么答案显然是(prod i^{s[i]})

    (s[i])直接数位(DP)就行了。

    代码

    #include<bits/stdc++.h>
    #define MAXN 65
    #define LL long long
    #define P 10000007
    using namespace std;
    LL f[MAXN][MAXN],c[MAXN][MAXN],N,cnt,ans=1;
    bool bit[MAXN];
    LL qp(LL x,LL y){
    	LL ret=1;
    	while(y){
    		if(y&1)ret=ret*x%P;
    		x=x*x%P;y>>=1;
    	}
    	return ret;
    }
    LL Solve(LL x){//有x个1的数的个数 
    	LL ret=0;
    	for(int i=cnt;i>=1;i--){
    		if(bit[i]){
    			ret+=c[i-1][x];
    			x--;
    		}
    		if(x<0)break;
    	}
    	return ret;
    	
    }
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("bzoj3209.in","r",stdin);
    	freopen("bzoj3209.out","w",stdout);
    	#endif
    	c[0][0]=1;
    	for(int i=1;i<=64;i++){
    		c[i][0]=c[i][i]=1;
    		for(int j=1;j<i;j++){
    			c[i][j]=c[i-1][j]+c[i-1][j-1];
    		}
    	}
    	scanf("%lld",&N);
    	N++;
    	while(N){
    		bit[++cnt]=(N&1);
    		N>>=1;
    	}
    	for(int i=1;i<=cnt;i++)ans=ans*qp(i,Solve(i))%P;
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    DP -- 递推
    二分查找题
    动态规划
    二分专题
    并查集
    三分法
    二分法
    插入排序
    排序小结
    Go go.mod入门
  • 原文地址:https://www.cnblogs.com/lrj998244353/p/8829985.html
Copyright © 2020-2023  润新知