codeforces 768 B. Code For 1(二分)
题目链接:http://codeforces.com/contest/768/problem/B
题意:给你一个数n和区间l,r,每次都能把任意数拆成n/2,n%2,n/2三个数,直到变成0和1,问区间l,r里有多少个1
题解:明显最后生成的是对称的,所以只要考虑一半就行,但是这里的n,l,r很大,有2的50次,最后起码有2的50
次长所以dfs直接生成字符串是不行的也会超时,但是r-l才10的5次所以可以考虑一下二分。加上这题的对称,二分很
方便。
附上二分的代码。二分的是位置,l到r之间的位置,mid值是num对应的中间值,然后取什么就看num%2是什么即可。
void binsearch(long long le , long long ri , long long num) {
long long mid = (le + ri) >> 1;
if(ri < l || le > r || le > ri)//注意要有le>ri退出,这很关键也是二分退出的条件。
return ;
if(mid < l) {
binsearch(mid + 1 , ri , num / 2);
}
else if(mid > r) {
binsearch(le , mid - 1 , num / 2);
}
else {
ans += num % 2;
binsearch(le , mid - 1 , num / 2);
binsearch(mid + 1 , ri , num / 2);
}
}
#include <iostream> #include <string> #include <cstdio> using namespace std; string s , sl; long long n , l , r , ans; long long dfs(long long num) { if(num == 1) { return 1; } return 1 + 2 * dfs(num / 2); } void binsearch(long long le , long long ri , long long num) { long long mid = (le + ri) >> 1; if(ri < l || le > r || le > ri) return ; if(mid < l) { binsearch(mid + 1 , ri , num / 2); } else if(mid > r) { binsearch(le , mid - 1 , num / 2); } else { ans += num % 2; binsearch(le , mid - 1 , num / 2); binsearch(mid + 1 , ri , num / 2); } } int main() { cin >> n >> l >> r; if(n == 0) { cout << 0 << endl; return 0; } long long count = dfs(n); binsearch(1 , count , n); cout << ans << endl; return 0; }