First One
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 142 Accepted Submission(s): 37
Problem Description
soda has an integer array
a1,a2,…,an . Let
S(i,j) be the sum of
ai,ai+1,…,aj . Now soda wants to know the value below:
∑i=1n∑j=in(⌊log2S(i,j)⌋+1)×(i+j)
Note: In this problem, you can consider
log20 as 0.
Input
There are multiple test cases. The first line of input contains an integer
T , indicating the number of test cases. For each test case:
The first line contains an integer
n
(1≤n≤105) , the number of integers in the array.
The next line contains
n integers
a1,a2,…,an
(0≤ai≤105) .
Output
For each test case, output the value.
Sample Input
Sample Output
Source
2015 Multi-University Training Contest 6
由于下取整log(sum)的值是很小的。可以枚举每个位置为开始位置,然后枚举每个log(sum)只需36*n的。中间j的累加和
推公式即可。
但是找log值相同的区间,需要用log(sum)*n的复杂度预处理出来,如果每次二分位置会超时。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define maxn 100007
ll num[maxn];
ll pos[maxn][36];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i = 0;i < n; i++){
scanf("%I64d",&num[i]);
}
num[n] = 0;
for(ll i = 0;i < 36; i++){
ll di = 1LL<<(i+1);
ll su = num[0];
int p = 0;
for(int j = 0;j < n; j++){
if(j) su -= num[j-1];
while(su < di && p < n){
su += num[++p];
}
pos[j][i] = p;
}
}
ll ans = 0,res;
for(int i = 0;i < n; i++){
ll p = i,q;
for(int j = 0;j < 36 ;j ++){
q = pos[i][j];
res = (j+1)*((i+1)*(q-p)+(p+q+1)*(q-p)/2);
ans += res;
p = q;
}
}
printf("%I64d\n",ans);
}
return 0;
}