2069: Saruman's Level Up (thinking enumeration + prime number decomposition to find the number of combinations)

Topic link: http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2069

题目:
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

The meaning of the question: that is, you are building a tower, and it starts with 0 floors. When the number of days on a certain day is converted into binary, and the number of each 1 is a multiple of 3, you can upgrade the tower to one level, such as On the 7th day, its binary is 111, with 3 1s, and the tower can be upgraded by one level. For example, on the 64th day, its binary is 111111, with 6 1s, and the tower can also be upgraded by one level. Enter a number of days and it will ask you how many floors the tower has on that day.

Ideas: The maximum number of days to enter is 10 to the 16th power, which is smaller than 2 to the 54th power. With a maximum of 54 bits, each bit can be enumerated, but it is not a simple enumeration and can be optimized. For example, the binary of 10101010, its lower limit is 10000000, and the number of upgrade towers of 10000000 is C(7,3)+C(7,6), which is actually the case when the first 1 of 10101010 is 0 , then consider the case where the first 1 is 1, subtract 10000000 from 10101010, cnt=1, cnt means that there are several 1s in front, which
is equal to 101010, and then continue to consider its lower limit, consider whether the second 1 is taken or not, until it reaches 0. But there are still a few special cases to be judged specially, see the code.

Code:

#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[55];//2的多少次方
long long vis[56],e[56];
long long a[55];//2的多少次方有多少个可以支配的1
vector <long long > primes;//质数表

void is_prime()//打出55以内的质数表
{
    memset(vis,0,sizeof(vis));
   long long m=sqrt(55+0.5);
    for(long long i=2; i<=m; i++)
   for(long long j=i*i; j<=55; 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<55; i++)
    {
        two[i]=pow(2,i);

    }

    a[0]=1;
    for(long long  i=1; i<=54; 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;
    long long ans=1;
    for(long long i=m+1; i<=n; i++)
        add_integer(i,1);
    for(long long i=1; i<=n-m; i++)
        add_integer(i,-1);
    for(long long i=0; i<primes.size(); i++)
        ans*=pow(primes[i],e[i]);
    return ans;
}

long long solve(long long x,long long cnt)
{
   long long sum1=0;
   for(long long i=3; i<=54; 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<55; 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)
                ans++;
        }
        printf("Day %lld: Level = %lld\n",N,ans);
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324489383&siteId=291194637
Recommended