gavanwanggw

导航

HDU 5358 First One(枚举)

First One

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 690    Accepted Submission(s): 205


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=1nj=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 (1n105), the number of integers in the array.
The next line contains n integers a1,a2,,an (0ai105).
 

Output
For each test case, output the value.
 

Sample Input
1 2 1 1
 

Sample Output
12
 

Source
 


题目大意:对题目中的式子求结果。


解题思路:由于0<=ai<=10^5,0<n<=10^5,所以0<=S(i,j)<10^12<2^34,设k=log2S(i,j)⌋+1则1<=k<=34,那么我们

每次枚举k时,求解出全部符合条件的(i+j),求和就可以。

而对于每个k,求解(i+j)时。先预处理出s[i](s[i]=a1+……+ai。则sum(i,j)=s[j]-s[i-1]),那么接下来仅仅需找到全部

满足2^(k-1)<=sum(i,j)<=2^k-1的(i+j)就可以。

对于求(i+j),我们再次枚举i,对每个i。求解出j的一个区间[l,r],使得对当前的i,有当l<=j<=r时,2^(k-1)

<=sum(i,j)<=2^k-1成立。那么对于当前的k,i,满足条件的i。j区间为[i,j](l<=j<=r)。这些区间相应同一个k和同一个i,这些区间的(i+j)的总和为:i*(r-l+1)+(r+l)*(r-l+1)/2。

枚举全然部的k和i,将全部和累加。

对于求解区间[l,r],如果k=a,在枚举i=b时,得到j的区间[L1,R1],那么同样的k,在枚举i=b+1时,得到j的区间[L2,R2]

一定不在区间[L1,R1]的左边,简单的说就是L2>L1。R2>R1。

因此查找l。r时能够降低范围。


代码例如以下:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define sqr(x) (x) * (x)
#define mod 1000000007
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;

ll fl[35]={0,0,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};
ll fr[35]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215,33554431,67108863,134217727,268435455,536870911,1073741823,2147483647,4294967295,8589934591,17179869183};
ll s[100005];
int main()
{
    ll i,j,k,n,a,l,r,t;
    scanf("%I64d",&t);
    while(t--)
    {
        scanf("%I64d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%I64d",&a);
            s[i]=s[i-1]+a;
        }
        ll ans=0;
        for(k=1;k<=34;k++)
        {
            l=1;
            r=0;

            //移位操作控制sum(i,j)的范围。也能够用数组
            //fl= k==1?

0:(1ll<<(k-1));fr=(1ll<<k)-1; for(i=1;i<=n;i++) { l=max(i,l); while(l<=n&&s[l]-s[i-1]<fl[k])//while(l<=n&&s[l]-s[i-1]<fl) l++; r=max(l-1,r); while(r+1<=n&&s[r+1]-s[i-1]>=fl[k]&&s[r+1]-s[i-1]<=fr[k])//while(r+1<=n&&s[r+1]-s[i-1]>=fl[k]&&s[r+1]-s[i-1]<=fr) r++; if(l<=r) ans+=(i*(r-l+1)+(r+l)*(r-l+1)/2)*k; //ans+=(i+l+i+r)*(r-l+1)/2*k; } } printf("%I64d\n",ans); } return 0; }


posted on 2017-06-22 21:37  gavanwanggw  阅读(199)  评论(0编辑  收藏  举报