zoukankan      html  css  js  c++  java
  • HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)

    HDU 5358

    题意:

    求∑i=1nj=in(log2S(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;
    }
    
    





  • 相关阅读:
    笔记2-斐波那契数列
    笔记1-排序
    C++ 顶层const和底层const ?
    C++指针常量与常量指针的区别?
    C++指针和引用的区别?
    函数指针, 指针函数?
    手机横竖屏问题
    Swift
    Swift 渐变色
    Swift guard 关键字
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7091354.html
Copyright © 2011-2022 走看看