您的位置:首页 > 其它

bzoj3209 花神的数论题 数位DP

2017-07-25 16:12 344 查看
一开始想的是先预处理出n位的答案,因为假设当前给出的数x有y位,那么y-1位的答案是固定的,我只要处理y位的答案就可以了,问题是这样太复杂。。。

设f[i][j]表示i位有j个1的答案,那么明显有f[i][j]=f[i-1][j]+f[i-1][j-1],表示第i位选0或1.

然后最后统计一下答案,就是每一种出现了多少次。。

其实挺简单的,基本想出来了,但是数位dp不熟,想的复杂了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
const int mo=10000007;
typedef long long ll;
ll n;
ll sum[100],f[100][100],g[100];
int wei
;
int tot;
ll ans;
inline void pre()
{
f[0][0]=1;
fo(i,1,60)
{
f[i][0]=1;
fo(j,1,i)
f[i][j]=f[i-1][j-1]+f[i-1][j];
}
}
ll solve(int x)
{
ll sum=0;
fd(i,tot,1)
{
if (wei[i]==1)
{
sum+=f[i-1][x];
--x;
}
if (x<0)break;
}
return sum;
}
ll pow(ll a,ll b)
{
ll ret=1;
while (b)
{
if (b&1)ret=ret*a%mo;
a=a*a%mo;
b>>=1;
}
return ret;
}
int main()
{
pre();
scanf("%lld",&n);
++n;
tot=0;
while (n)
{
wei[++tot]=n&1;
n>>=1;
}
ans=1ll;
fo(i,1,tot)
ans=ans*pow(i,solve(i))%mo;
printf("%lld\n",ans%mo);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: