題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5358
題意:給你一個串數和一個公式,求這個公式的答案。
思路:直接暴力一定會超時的,而且這道題很卡時間,交C++的都TLE了。怎麼優化才能不超時,於是就有了尺取法,其實就相當於兩個分別指向區間左右指針不斷更新區間內容的過程。
尺取法(two point)就是兩個指針表示區間[l,r]的開始與結束然後根據題目來將端點移動,是一種十分有效的做法,適合連續區間的問題。
尺取法(two point)基本過程分爲4步:
1.初始化左右端點
2.不斷擴大右端點,直到滿足條件
3.如果第二步中無法滿足條件,則終止,否則更新結果
4.將左端點擴大1,然後回到第二步
代碼:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 100005
#define LL __int64
int a[N];
LL sum[N];
int getM(LL a)
{
return !a?1:(int)log2(a*1.0)+1;
}
int main()
{
int T,n,i,j,m;
LL ans,pl,pr,p;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ans=sum[0]=0;
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
m=getM(sum[n]);
for(i=1; i<=m; i++)
{
int l=1,r=0;
if(i==1)
pl=0;
else
pl=1LL<<(i-1);
pr=(1LL<<i);
for(j=1; j<=n; j++)
{
l=max(j,l);
while(l<=n&&sum[l]-sum[j-1]<pl)
l++;
r=max(l-1,r);
while( (r+1<=n) && (sum[r+1]-sum[j-1]>=pl) && (sum[r+1]-sum[j-1]<pr) )
r++;
if(l<=r)
ans+=(LL)(l+r)*(r-l+1)/2*i+(LL)j*(r-l+1)*i;
}
}
printf("%I64d\n",ans);
}
return 0;
}