CF 768B
題意:
In each operation Sam must remove any element x, such that x>1, from the list and insert at the same position x/2,x%2,x/2 sequentially. He must continue with these operations until all the elements in the list are either 0 or 1.
給定一個數N,對大於1的數在原來的位置拆分爲N/2,N%2,N/2三個數。對拆分出的大於1的數一樣進行拆分,直至全部的數均爲0或1。
Now the masters want the total number of 1s in the range l to r (1-indexed).
對拆分後的0/1序列,詢問L到R區間中1的數量
相似於線段樹的區間查詢
思路1:簡單題,遞歸思想。對於給定的N,能夠計算出最終0/1序列的長度。遞歸模擬,一層層往下分解,將獲得的數分解到序列的對應指定位置中,當沒法分解時則返回值,最後遞歸獲得區間內全部的1的個數
這裏我擔憂被卡,用了一個位運算小優化。其實不用也能夠。
Code:
#include<cstdio>
typedef long long ll;
ll n,ql,qr,len=1,ans;
ll dfs(ll n,ll l,ll r){
if(n==0||l>qr||r<ql) return 0;
if(n==1) return 1;
ll mid=l+r>>1;
return dfs(n>>1,l,mid-1)+dfs(n&1,mid,mid)+dfs(n>>1,mid+1,r);
}
int main(){
scanf("%I64d%I64d%I64d",&n,&ql,&qr);
for(ll x=n;x>1;x>>=1,len=len<<1|1);
ans=dfs(n,1,len);
printf("%I64d\n",ans);
return 0;
}
思路2:求出區間端點的前綴和相減,拆分的個數符合f(n)=2*f(n-1)+1,而n拆後的區間和必定是n,因此用二分找出端點位置便可
優化