HDU 4321 Arcane Numbers 2 按位处理, 想法计数题
2015-08-12 01:23
344 查看
题目大意:
就是对于给出的A, B, N, A <= 1e4, B <= 1e16, N <= 1e12, 统计在B + A, B + 2*A, B + 3*A, B + 4*A.... B + N*A这N个数的二进制表示法下一共有多少个1
大致思路:
这个题调了好久...想法虽然可行但是写错了几个细节的位置...于是调了半个小时才调过....感觉思路明确了复杂度也就清楚了
思路写在代码注释里了
代码如下:
Result : Accepted Memory : 1620 KB Time : 140 ms
就是对于给出的A, B, N, A <= 1e4, B <= 1e16, N <= 1e12, 统计在B + A, B + 2*A, B + 3*A, B + 4*A.... B + N*A这N个数的二进制表示法下一共有多少个1
大致思路:
这个题调了好久...想法虽然可行但是写错了几个细节的位置...于是调了半个小时才调过....感觉思路明确了复杂度也就清楚了
思路写在代码注释里了
代码如下:
Result : Accepted Memory : 1620 KB Time : 140 ms
/* * Author: Gatevin * Created Time: 2015/8/11 23:31:36 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; /* * 首先要求的是B + A, B + 2*A, .... B + N*A这N个数的二进制中总共有多少个1 * 那么我们按位一步一步来, 先统计N个数中第K位是1的个数 * 第K位按照二进制从右向左数, 从1开始数 * 那么不难发现对于第K位B + T*A 和 B + T*A + (1 << K)*A一定是一样的 * 那么我们在计算第K位的时候对于 1 <= T <= (1 << K) - 1计算即可 * 对于B + i*A, 1 <= i <= (1 << K) - 1相同的贡献个数为 (N - i)/(1 << K) + 1个这里是整数除法 * 但是由于K可以比较大, 所以对于第K位不能暴力枚举所有可能的T * 那么当(1 << K) <= A的时候我们暴力枚举 * 当(1 << K) > A时, 我们考虑这样一个事实: * 不难发现如果当前第i项 B + i*A对于(1 << K)取模之后剩下的部分, 在接下来添加A的过程中会有连续的一段不向第K位二进制进位 * 那么就会出现连续的B + i*A, B + (i + 1)*A,...., B + j*A一整段的第K位都是0, 然后又连续一段是1, 两者交替的情况 * 于是这样我们只需要计算连续的一段多长就可以了, 由于(1 << K) > A, 前面一段对(1 << K)取模剩余res的时候接下来一段长度是((1 << K) - res - 1)/A * 那么枚举第K位的时间复杂度是O(log(B + A*N))而每一次枚举, 需要计算区间[1, (1<<K) - 1], 一段区间计算次数是大约是(1<<K)/(((1 << K) - res - 1)/A)次 * 而(1 << K) / (((1 << K) - res - 1)/A)也就是是O(A)的级别 * 于是整体复杂度也就是O(log(B + A*N)*A) */ int T; lint A, B, N; lint solve() { lint ans = 0; lint mx = B + A*N; for(int K = 1; (1LL << (K - 1)) <= mx; K++)//从右向左第K位 { lint L = 1LL << (K - 1); lint S = 1LL << K; lint rest = (B + A) % L; int now = (B + A) & L ? 1 : 0;//当前第K位是0还是1 lint T = 1; while(T <= S && T <= N) { lint step = (L - rest - 1) / A;//接下来会有的连续的now(0 or 1)的个数 step = min(step, min(N - T, S - T)); //也就是说[T, T + step]都是now //一共step + 1个, 对答案的贡献是sigma((N - i) / (1 << K)) T <= i <= T + step //cout<<L<<" "<<rest<<" "<<now<<" "<<T<<" "<<step<<" "<<K<<" "<<ans<<endl; //getchar(); if((N - T) / S + 1 == (N - (T + step))/S + 1) ans += (step + 1)*((N - T)/S + 1) * now; else { lint mid = (N - T) / S * S;//[mid, N - T]这一段都是相同的, [N - (T + step), mid - 1]是相同的 (相同指的是B + (T + (1 << K))*A的个数相同) ans += ((N - T) / S + 1) * (N - T - mid + 1) * now; ans += ((N - (T + step)) / S + 1) * (mid + T + step - N) * now; } rest = (rest + (step + 1)*A) % L; T += step + 1; now = (B + T*A) & L ? 1 : 0;//接下来是相反的连续段 } } return ans; } int main() { scanf("%d", &T); for(int cas = 1; cas <= T; cas++) { scanf("%I64d %I64d %I64d", &A, &B, &N); printf("Case #%d: %I64d\n", cas, solve()); } return 0; }
相关文章推荐
- iOS包管理工具Cocoapods的安装与使用
- HDUOJ_1875(最小生成树)(畅通工程再续)(克鲁斯卡尔和prim两种方法解)
- 黑马程序员——ios学习笔记 OC Foundation—NSArray&NSDictionary
- Ray Wenderlich的swift教程02--引用类型和值类型
- Hibernate缓存非常烦人,想要最新数据连session.clear都不好使
- 黑马程序员——ios学习笔记 OC Foundation—NSString
- Quartz2D复习(四) --- 图层CALayer和动画CAAnimation
- Scala 深入浅出实战经典 第5讲:Scala数组操作实战详解
- 黑马程序员——ios学习笔记 OC 分类
- 数据结构基础温故-7.排序
- 黑马程序员——ios学习笔记 OC 协议&Block
- F - Friends-HDU 5305
- 事件引入和本质
- golang 数组切片(一)
- 互联网电商大数据环境 ——大数飓数据分析实践培训精华笔记(五)——数据仓库维度建模实例
- context.drawImage绘制图片
- nginx服务器去掉url中的index.php 和 配置path_info
- DOS命令大全
- 输入一个int型数据,计算出该int型数据在内存中存储时1的个数。
- UCenter修改