题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5358
一开始一直以为是一道数学题,在找有什么规律化简Log2(S(i,j)),结束了以后才造 ⌊log2(x)⌋ 即表示x的二进制的最高位。
总结了以下几点:
1、直接暴力肯定会T,status上基本上都是T
2、⌊log2(S(i,j))⌋ +1,表示S(i,j)用二进制表示的位数
3、S(i,j)可以由S(j) - S(i) 表示
4、用尺取法进行枚举区间在区间[2^(k-1),2^k]内的[ i, [ l, r ]],方法如下
1)固定 i
2)找到大于等于L的第一个 l,和大于等于R的第一个 r+1(即 r 小于 R )
3)排除不符合条件的 l 和 r
3)计算 ( i + j ) 的值
4)改变 i 值重复以上过程
#include<stdio.h> #include<math.h> const int MAXN = 100010; int T; int n; long long a[MAXN], sum[MAXN]; long long solve(long long L, long long R){ long long ans = 0; int l, r; l = 1; r = 0; //定义两个标记,l和r for( int i = 1; i <= n; ++i){ if( l < i ) l = i; if( r + 1 < i) r = i - 1; while( l <= n && sum[l] - sum[i-1] < L) l++; while( r+1 <= n && sum[r+1] - sum[i-1] < R ) r++; //循环,使得 sum(i,l) >= L sum(i,r) < R,即上界和下界 if( l > r) continue; if( sum[r]-sum[i-1] < L || sum[r] - sum[i-1] >= R ) continue; if( sum[l]-sum[i-1] < L || sum[l] - sum[i-1] >= R ) continue; //排除不符合条件的情况 ans += ( long long )(r-l+1)*i+(long long )(r-l+1)*(r+l)/2; //求(i,l)到(i,r) 的 i+j 和 } return ans; } int main(){ long long ans; scanf("%d", &T); while(T--){ ans = 0; scanf("%d", &n); sum[0] = 0; for( int i = 1; i <= n; ++i){ scanf("%I64d",&a[i]); sum[i] = sum[i-1] + a[i]; } //数据读取,sum存储从第一个元素到第i个元素的和 for( int k = 1; k <= 34; ++k){ ans += (long long )k * solve(pow(2,k-1),pow(2,k)); } ans += solve(0,1); //加上[0,1)区间 printf("%I64d\n",ans); } }
代码学习了:http://blog.csdn.net/zjck1995/article/details/47321881
ACM毕竟是编程竞赛,数学问题也要结合计算机相关知识进行考虑。
时间: 2024-10-17 15:50:56