hdu 5358 First One [枚举+尺取法]

来源:互联网 发布:it was not until 编辑:程序博客网 时间:2024/05/18 01:00

题意:给你n个数,求他给出的求和式

题解:由于求和式中含有log2,当我们枚举左端点的时候,右端点在一定范围内log2值是不会变的,所以我们可以对每一种log2的取值做枚举,然后枚举每一个左端点,再找到右端点符合条件的范围,但是假如用二分查找右端点得到结果时间复杂度n*logsum*logn,TLE,所以可以考虑用尺取法,所以总的复杂度为n*logn。

AC代码:

#include<stdio.h>#include<math.h>typedef long long ll;ll a[100005],sum[100005];ll cf2[40];  void init() { ll k = 1; for(int i=0; i<=34; ++i) { cf2[i] = (k<<(i)); } } int main(){init();ll T;scanf("%lld",&T);while(T--){ll n;scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}sum[n+1]=(ll)1E17;ll ans=0,gg;for(int i=1;i<=n;++i){ int p=i; while(sum[p]==sum[i-1]&&p<=n+1)++p; --p; if(p>=i)ans+=(ll)(i*3+p)*(ll)(p-i+1)/2; }ll now=1;ll last=0;for(int j=0;j<=33;j++){ int p1=0,p2=0;for(int i=1; i<=n; ++i){ ll adc = sum[i-1] + cf2[j]; while(sum[p1]<adc && p1<=n)++p1; adc = sum[i-1] +cf2[j+1]; while(sum[p2]<adc && p2<=n+1)++p2;--p2; if(p2>=p1&&p2)ans+=(j+1)*(ll)(i*2+p1+p2)*(ll)(p2-p1+1)/2;}}printf("%lld\n",ans);}return 0;}



原创粉丝点击