题意:
求∑?i=1?n??∑?j=i?n??(?log?2??S(i,j)?+1)?(i+j)。
思路:
S(i,j) < 10^10 < 2^34,所以log2(S)+1的值只可能在1~35之间。由于log变化缓慢的函数特性,我们可以S(i,n)分作多个相同log值的区间来计算,用pos[i][j]预处理记录每个以i为起点,log(s)值为j的区间的右边界,即可优化至nlogn的复杂度。
主要是写起来比较难一些,一些细节比较纠结,一定思路理清后再写。
ps.此题卡常数毫无人性,一定记得预处理好区间映射,否则n(logn)^2也得跪。。
code:
/* * @author Novicer * language : C++/C */ #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> #define INF 2147483647 #define cls(x) memset(x,0,sizeof(x)) #define rise(i,a,b) for(int i = a ; i <= b ; i++) using namespace std; const double eps(1e-8); typedef long long lint; const int maxn = 100000 + 5; lint a[maxn]; lint pos[maxn][34]; lint two[34] = {2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728, 268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184}; int main(){ int t ; cin >> t ; while(t--) { int n; cin >> n; for(int i = 1 ; i <= n ; i++){ scanf("%I64d",&a[i]); } for(int i = 0 ; i < 34 ; i++){ lint sum = a[1]; int right = 1; for(int j = 1 ; j <= n ; j++){ if(j != 1) sum -= a[j-1]; while(sum < two[i] && right <= n) sum += a[++right]; pos[j][i] = right;//以j为起点,log2(sum+1)值为i的区间右边界为right } } lint ans = 0; for(int i = 1 ; i <= n ; i++){ lint l = i; lint r; for(int j = 0 ; j < 34 ; j++){ r = pos[i][j]; ans += (1+j) * ((i) * (r-l) + (r+l-1)*(r-l)/2);//将相同log值区间的(i+j)累加起来 l = r; } } cout << ans << endl; } return 0; }
版权声明:博主表示授权一切转载:)
HDU 5358(2015多校联合训练赛1006) First One (区间合并+常数优化)
原文地址:http://blog.csdn.net/qq_15714857/article/details/47328941