传送门:点击打开链接
题意:就是你在建一个塔,开始它是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; }