P4317 花神的数论题

传送门

考虑把 $sum$ 值相同的一起用快速幂计算

枚举 $sum=i$ ,然后可以用数位 $dp$ 求有多少小于 $n$ 的二进制下恰好有 $i$ 个 $1$ 的数的个数

注意不要把个数取模,因为个数是幂次

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=233,mo=10000007;
inline ll fk(ll x) { return x>=mo ? x-mo : x; }
ll n,C[N][N],ans=1;
ll b[N],res;
void dfs(int p,int t)
{
    if(!t) { res++; return; }
    if(!p) return;
    if(!b[p]) dfs(p-1,t);
    else res+=C[p-1][t],dfs(p-1,t-1);
}
ll ksm(ll x,ll y)
{
    ll res=1;
    while(y)
    {
        if(y&1) res=res*x%mo;
        x=x*x%mo; y>>=1;
    }
    return res;
}
int main()
{
    n=read();
    for(int i=0;i<64;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    int len=0; ll t=n; while(t) b[++len]=t&1,t>>=1;
    for(int i=1;i<=len;i++)
    {
        res=0; dfs(len,i);
        ans=ans*ksm(i,res)%mo;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2019-09-14 10:39  LLTYYC  阅读(145)  评论(0编辑  收藏  举报