题意:http://acm.hdu.edu.cn/showproblem.php?pid=4321
给定a和b、n,让你求b + a, b + 2 * a, .......b + n * a里面有多少1.
题解:
这个题解是以前做过多校之后看的。以前看了很久很久很久很久都没看懂。 现在二十分钟左右看懂了。 是我以前心不在焉吗?
按位统计计算,如果枚举 那么复杂度就是 64 * N
第一条
当统计第K位的时候 可以注意到 第 B+T*A 和 B+(T+2^(K+1))*A 位是相同的
那么 第K位的时候 只需要统计2^(K + 1) - 1次就可以了
第二条
当统计第K位的时候 可以注意到 连续的 (2^K)/A都是连续的0 或者连续的1 所以可以考虑直接连续记录(2^K)/A个结果。
那么 第K位的时候 只需要统计N / ((2^K)/A)次就可以了
综合 第一条 第二条 那么 第K位的时候 只需要统计 2^K/((2^K)/A) 复杂度 变为O(A)
总复杂度为64*A
#include <cstdio>
#include <cstring>
int main(){
int t;
__int64 a, b, n;
scanf("%d", &t);
for(int cas=1; cas<=t; ++cas){
scanf("%I64d%I64d%I64d",&a,&b,&n);
__int64 cnt = 0;
__int64 max = b + a * n;
for(__int64 i=0; i<64; ++i){ // 一位一位统计
__int64 m = 1LL << i;
__int64 mm = m;
if(m > max)
break;
m <<= 1;
__int64 cur = a + b;
__int64 j = 0;
while(j < m && j < n){
__int64 upper = cur + (mm - (cur % mm)) - 1LL;
__int64 step = (upper - cur) / a + 1LL;
if(j + step >= n){
step = n - j;
}
if(j + step >= m){
step = m - j;
}
if(cur & (1LL << i)){
cnt += step * (n / m);
if(j + step < (n % m)){
cnt += step;
}else if(j < (n % m)){
cnt += ( n % m ) - j;
}
}
cur += a * step;
j += step;
}
}
printf("Case #%d: %I64d\n", cas, cnt);
}
return 0;
}