bzoj 3209: 花神的数论题【数位dp】
参考:https://blog.csdn.net/sunshinezff/article/details/51049132
非典型数位dp
首先预处理,设f[i][j]为以0开头的i位数中1的个数为j的数的数量,g[i][j]为以1开头的i位数中1的个数为j的数的数量;转移是 f[i][j]=f[i-1][j]+g[i-1][j],g[i][j]=f[i-1][j-1]+g[i-1][j-1]
然后做数位dp,对于n在二进制下为1的位统计这样的1的个数出现过几次,然后快速幂即可
#include<iostream>
#include<cstdio>
using namespace std;
const int N=65,mod=10000007;
long long n,f[N][N],g[N][N];
long long ksm(long long a,long long b)
{
long long r=1ll;
while(b)
{
if(b&1)
r=r*a%mod;
a=a*a%mod;
b>>=1;
}
return r;
}
int main()
{
scanf("%lld",&n);
f[1][0]=1,g[1][1]=1;
for(int i=2;i<=60;i++)
for(int j=0;j<=i;j++)
{
f[i][j]=f[i-1][j]+g[i-1][j];
if(j>0)
g[i][j]=f[i-1][j-1]+g[i-1][j-1];
}
long long t=0,c=0,ans=1;
for(t=0;(1ll<<t)<=n;t++);
for(;t;t--)
if(1ll<<(t-1)&n)
{
for(int i=1;i<=t;i++)
ans=ans*ksm(i+c,f[t][i])%mod;
if(c)
ans=ans*c%mod;
c++;
}
printf("%lld\n",ans*c%mod);
return 0;
}