花神的数论题 bzoj-3209
题目大意:sum(i)表示i的二进制表示中1的个数,求$\prod\limits_{i=1}^n sum(i)$
注释:$1\le n\le 10^{15}$。
想法:喷一下题目...神tm数论题,明明是个dp。
显然,如果稍微打个表的话就可以发现,有很多数的sum是相等的,我们不想重复乘这么多次,所以我们想到将所有sum相等的数弄到一起然后快速幂。这样,就不难想到数位dp
状态:dp[i][j]表示i位,sum值是j的个数。
转移是容易的,按照数位dp的边界特判就行了。
最后,附上丑陋的代码... ...
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long int ll;
const int MAXN=60+5;
const ll mod=10000007;
ll n, Ans;
ll C[MAXN][MAXN];
int l,wei[MAXN];
void pre()
{
for (int i=0;i<=60;++i)
C[i][0]=1;
for(int i=1;i<=60;i++)
for(int j=1;j<=i;++j)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
ll Solve(int x)
{
ll sum=0;
for(int i=l;i>=1;i--)
{
if(wei[i]==1)
{
sum+=C[i-1][x];
--x;
}
if(x<0) break;
}
return sum;
}
ll quick_power(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1) ans=(ans*x)%mod;
y>>=1;
x=(x*x)%mod;
}
return ans;
}
int main()
{
pre();
scanf("%lld",&n);
++n;
l=0;
while(n)
{
wei[++l]=n&1;
n>>=1;
}
Ans=1ll;
for(int i=1;i<=l;i++)
{
Ans=Ans*quick_power(i,Solve(i))%mod;
}
printf("%lld\n",Ans);
return 0;
}
小结:有意思...别被题面迷惑了(@EdwardFrog)