First One
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 831 Accepted Submission(s): 253
Note: In this problem, you can consider log20 as 0.
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).


1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll ; 4 const int M = 1e5 + 10 ; 5 ll n ; 6 ll a[M] ; 7 ll ure[M] ; 8 ll tot ; 9 void solve () { 10 for (int k = 1 ; k < 40 ; k ++) { 11 ll low = 1ll << k , sum = 0 ; 12 for (int i = 1 , j = 0 ; i <= n ; i ++) { 13 while (j <= n && sum < low) sum += a[++j] ; 14 if (sum >= low) tot += i * (n-j+1) + ure[j] ; 15 else break ; 16 sum -= a[i] ; 17 } 18 } 19 printf ("%I64d\n" , tot) ; 20 } 21 22 int main () { 23 int T ; 24 scanf ("%d" , &T ) ; 25 while (T --) { 26 scanf ("%I64d" , &n) ; 27 for (int i = 1 ; i <= n ; i ++) scanf ("%I64d" , &a[i]) ; 28 29 ure[n+1] = 0 ; 30 tot = 0 ; 31 for (int i = n ; i >= 1 ; i --) { 32 ure[i] = ure[i+1] + i ; 33 tot += i * (n-i+1) + ure[i] ; 34 } 35 36 solve () ; 37 } 38 return 0 ; 39 }
比赛的时候思路很明确,log2 + 1那部分最多就1~40,所以枚举一下,每次枚举时用 尺取法 求得所有区间即可。
所以总的复杂度为O(40*n) , 后来又注意到尺取法的界限判断是要映射一下,所以复杂度变成了O(40*n*log40) ,然后oj就给我判TLE了,
这只能说出题人卡的实在是。。。。是在下输了
当然赛后看标成时,还是发现写法漏洞很大。
1.标成上他把log2 和 1 这两部分分开来处理,算1这部分O(n)的复杂度。
2.因为log2那部分是个浮动的区间和,所以直接用 尺取法 不行。(因为我的作法是:比如说枚举到5时,我想利用 尺取法 得到所有映射后为5的区间)
但标成很机智的改成了:枚举到i时,当前多少个区间映射后的值是>=i的,然后加上他们。如果每次枚举都这么做,你会发现区间映射值为5的就加了5次,
为6的被加了6次。
因此把浮动的区间和,变成了一个定值,那么 尺取法 就又能发挥它的作用了。