2069: Saruman’s Level Up(思维枚举+质数分解求组合数)

原创 2018年04月16日 20:34:54

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

题意:就是你在建一个塔,开始它是0层,当某一天的天数,转化为2进制,每一位为1的个数是3的倍数,就可以把塔升级一层,比如第7天,它的二进制为111,3个1,塔就可以升级一层,比如第64天,它的二进制为111111,6个1,塔也可以升级一层。 输入一个天数,问你当天,塔的层数是多少。

思路: 输入最大的天数是10的十六次方,比2的54次方小。就最多54位,就可以每位枚举下,但不是单纯的枚举,可以优化处理下。 比如说10101010这个二进制,它的下限就是10000000,10000000的升级塔的次数就是C(7,3)+C(7,6), 这个算的其实就是10101010的第一个1为0的时候的情况,然后考虑第一个1为1的情况 就把10101010减去10000000,cnt=1,cnt表示前面有几个1,
等于101010,然后继续考虑它的下限,考虑第二个1是否取不取,直到减到0。但是还有个特例要特殊判断一下,见代码。

代码:

#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++)
        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++)
        {
            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;
}

版权声明:转载注明出处 https://blog.csdn.net/qq_36300700/article/details/79966066

CSU2069: Saruman’s Level Up

DescriptionSaruman’s army of orcs and other dark minions continuously mine and harvest lumber out of...
  • qq_37064135
  • qq_37064135
  • 2018-04-15 21:04:10
  • 82

POJ3069 Saruman's Army

Saruman's Army Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4214   ...
  • u012846486
  • u012846486
  • 2014-10-30 11:31:32
  • 840

2069: Saruman’s Level Up(思维枚举+质数分解求组合数)

题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2069 题目: Description Saruman’s army of or...
  • qq_36300700
  • qq_36300700
  • 2018-04-16 20:34:54
  • 117

CSU 2069 Saruman’s Level Up(组合数+枚举)

CSU 2069 Saruman’s Level Up 题意 ​ 求0-n之间,二进制中1的个数为3的倍数的数有多少个。 解题思路   首先我们知道,剩余位数=length-1-当...
  • qq_36258516
  • qq_36258516
  • 2018-04-17 07:59:04
  • 87

Saruman's Army

#include #include #include using namespace std;#define MAX_N 2000int N,R; int X[MAX_N];void solve(...
  • NoMasp
  • NoMasp
  • 2015-05-19 15:17:11
  • 2065

Poj 3069 Saruman's Army【贪心】

Saruman's Army Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5742   Accepted: 2...
  • liuke19950717
  • liuke19950717
  • 2015-10-01 22:57:45
  • 1045

组合数的模的几种求法总结

11111
  • u013749267
  • u013749267
  • 2014-08-24 18:02:47
  • 1137

Saruman’s Level Up Gym - 101656G CSU 2069

题目链接: https://vjudge.net/problem/Gym-101656G // 也可在CSU 2069提交题意: 给你一个十进制的数 二进制 111,也就是十进制的7表示第一个等级,问...
  • Hazard679
  • Hazard679
  • 2018-04-17 09:06:58
  • 10

CSU 2069 Saruman‘s Level Up(数位dp/组合计数)

大致题意:让你求在1到n范围内转换成二进制后1的个数是3的倍数的数字的个数。 典型的数位dp。设置dp[len][x]表示长度为len的二进制数字中含有x个1的个数。显然又转移方程dp[...
  • u013534123
  • u013534123
  • 2018-04-17 21:51:29
  • 5

2069: Saruman’s Level Up(排列组合+分段打表)

传送门:点击打开链接 题意:就是你在建一个塔,开始它是0层,当某一天的天数,转化为2进制,每一位为1的个数是3的倍数,就可以把塔升级一层,比如第7天,它的二进制为111,3个1,塔就可以升级一层,比...
  • tianwei0822
  • tianwei0822
  • 2018-04-19 17:05:35
  • 11
收藏助手
不良信息举报
您举报文章:2069: Saruman’s Level Up(思维枚举+质数分解求组合数)
举报原因:
原因补充:

(最多只允许输入30个字)