hdu5358 ( First One )数学+思维
题目链接
题意:让你求这个公式的值。
思路:公式中最重要的就是对数,对2取对数并向下取整,那么答案就是一块一块的.
我们遍历每一个左端点 li,对每种可能的取对数得到的值进行讨论。
假设当前对数值是 x,那么 x贡献的区间 x,y满足一个条件
sum[x]−sum[li−1]>=2x且 sum[x]−sum[li−1]<2x+1。
把这部分的贡献加到答案里面,然后不停的找下一个位置即可。
详细细节见代码。
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 1e5 +11;
LL t,n,a[N];
LL f[N][33];
LL ans,sum[N];
int main(){
for(scanf("%d",&t);t;t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=n+1;i<=n+100;i++)sum[i]=sum[i-1];
ans=0;
for(LL i=1;i<=n;i++){
LL l=i,pre=0,r=i;
for(LL j=1;j<=35;j++){
if(a[i]>=(1ll<<j)){pre=j;continue;}
LL pos=lower_bound(sum+i+1,sum+1+n,sum[i-1]+(1ll<<j))-sum;
r=pos;
if(pos<=l){pre=j;continue;}
if(pos==1+n){
ans+=(pre+1)*i*(n-l+1);
ans+=(pre+1)*(l+n)*(n-l+1)/2;
//cout<<j<<endl;
break;
}else{
ans+=(pre+1)*i*(pos-l);
ans+=(pre+1)*(l+pos-1)*(pos-l)/2;
pre=j;
l=pos;
}
}
}
printf("%lld\n",ans);
}
return 0;
}