# 2069: Saruman’s Level Up（思维枚举+质数分解求组合数）

Description
Saruman’s army of orcs and other dark minions continuously mine and harvest lumber out of the land surrounding his mighty tower for N continuous days. On day number i, Saruman either chooses to spend resources on mining coal and harvesting more lumber, or on raising the level (i.e., height) of his tower. He levels up his tower by one unit only on days where the binary representation of i contains a total number of 1’s that is an exact multiple of 3. Assume that the initial level of his tower on day 0 is zero. For example, Saruman will level up his tower on day 7 (binary 111), next on day 11 (binary 1011) and then day 13, day 14, day 19, and so on. Saruman would like to forecast the level of his tower after N days. Can you write a program to help?

Input
The input file will contain multiple input test cases, each on a single line. Each test case consists of a positive integer N < 1016, as described above. The input ends on end of file.

Output
For each test case, output one line: “Day N: Level = L”, where N is the input N, and L is the number of levels after N days.

Sample Input
2
19
64
Sample Output
Day 2: Level = 0
Day 19: Level = 5
Day 64: Level = 21

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>

using namespace std;
const long long inf=1e16;
long long N,sum,id,cnt,ans,N1;
long long two[56];//2的多少次方
long long vis[56],e[56];
long long a[56];//2的多少次方有多少个可以支配的1
vector <long long > primes;//质数表

void is_prime()//打出55以内的质数表
{
memset(vis,0,sizeof(vis));
long long m=sqrt(56+0.5);
for(long long i=2; i<=m; i++)
for(long long j=i*i; j<56; j+=i)
vis[j]=1;
for(int j=2; j<55; j++)
if(!vis[j])
primes.push_back(j);
}

void add_integer(long long n,long long d )//质因数分解
{
for(long long i=0; i<primes.size(); i++)
{
while(n%primes[i]==0)
{
n/=primes[i];
e[i]+=d;
}
if(n==1)
break;
}
}

void init()
{
for(long long i=0; i<56; i++)
{
two[i]=pow(2,i);

}

a[0]=1;
for(long long  i=1; i<56; i++)
{
a[i]=i;
}
}

long long C(long long n, long long m)//用质因数分解求组合数
{
memset(e,0,sizeof(e));
if(m<n-m)
m=n-m;
double ans1=1;
long long ans;
for(long long i=m+1; i<=n; i++)
for(long long i=1; i<=n-m; i++)
for(long long i=0; i<primes.size(); i++)
{
if(e[i]!=0)
{
ans1*=(double)pow(primes[i]*1.0,e[i]*1.0);//pow返回值为double，用整形会卡精度
}
}
ans=ans1;
return ans;
}

long long solve(long long x,long long cnt)
{
long long sum1=0;
for(long long i=3; i<56; i+=3)
{
if(x>=i-cnt&&i-cnt>=0)
{
sum1+=C(x,i-cnt);
}

}
return sum1;
}

int main()
{
init();
is_prime();
while(scanf("%lld",&N)!=EOF)
{
ans=0;
cnt=0;//前面有几个1
N1=N;
while(N1)
{
for(long long i=0; i<56; i++)
{
if(N1>two[i]&&N1<two[i+1])
{

id=i;
break;
}
if(N1==two[i])
{
id=i;
break;
}
}
ans+=solve(a[id],cnt);
cnt++;
N1=N1-two[id];
if(N1==0&&cnt%3==0&&N%2!=1)//当我前面的1的个数是3的倍数且二进制最后一位为0的话，会少算一次.
ans++;
}
printf("Day %lld: Level = %lld\n",N,ans);
}
return 0;
}



• 评论

2

• 上一篇
• 下一篇