传送门:点击打开链接
题意:就是你在建一个塔,开始它是0层,当某一天的天数,转化为2进制,每一位为1的个数是3的倍数,就可以把塔升级一层,比如第7天,它的二进制为111,3个1,塔就可以升级一层,比如第64天,它的二进制为111111,6个1,塔也可以升级一层。 输入一个天数,问你当天,塔的层数是多少。
思路:n为10^16,二进制最多54位,组合数不会爆long long,首先考虑2的n(1<=n<=55)次幂数,也就是二进制形式为1,10,100...的情况,用组合数求出这些数的答案。然后再加减去重得答案,表达能力有限,可以结合代码理解。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 55;
ll a[N],n,bit[N];
ll gb(ll x){
ll tp[N],k=0;
while(x){
tp[k++]=x%2;
x/=2;
}
for(ll i=k-1;i>=0;i--)
bit[k-1-i]=tp[i];
return k;
}
ll C(ll n,ll m){
if(m==0) return 1;
if(n<0||m<0||n<m) return 0;
ll s=1;
for(ll i=1;i<=m;i++)
s=s*(n-i+1)/i;
return s;
}
void init(){
a[1]=a[2]=a[3]=0;
ll s=0;
for(int i=4;i<N;i++){
for(int j=2;j<=i-2;j+=3)
s+=C(i-2,j);
a[i]=s;
}
}
int main(){
///cout<<C(59,29)<<endl;
init();
while(cin>>n){
ll m=n+1;
ll bc=gb(m),ans=0,ct=0;
ans+=a[bc];
bc=gb(n);
for(ll i=0;i<bc;i++)
if(bit[i]==1) ct++;
if(ct==1||ct==bc) {
printf("Day %lld: Level = %lld\n",n,ans);
continue;
}
for(ll i=2;i<bc;i+=3) ans+=C(bc-1,i);
ll idx=0,ct0=0,ct1=0;
while(idx<bc){
while(bit[idx]&&idx<bc) ct1++,idx++;
while(bit[idx]==0&&idx<bc) ct0++,idx++;
for(ll i=1;i<=ct0;i++)
for(ll j=3;j<=bc;j+=3)
ans-=C(ct0,i)*C(bc-idx,j-ct1-i);
ct0=0;
}
printf("Day %lld: Level = %lld\n",n,ans);
}
return 0;
}