19牛客多校 3 G
題意:給你一個數組,求滿足一個區間(l,r)的最大值大於等於其區間和的1/2(l!=r)
思路:區間分治 把最大值作爲分界線。
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <iterator>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=3e5+10;
int a[N],lg[N],dp[N][20],n;
ll sum[N],sum1[N],ans;
void RMQ()
{
for(int i=1;i<=n;i++)
dp[i][0]=i;//裏面存的下標
for(int i=1;(1<<i)<=n;i++)
{
int d=(1<<i);
for(int j=1;j+d-1<=n;j++)
{
dp[j][i]=a[dp[j][i-1]]>=a[dp[j+(1<<(i-1))][i-1]]?
dp[j][i-1]:dp[j+(1<<(i-1))][i-1];
}
}
}
void solve(int x,int y)
{
if(x>=y)
return;
int k=lg[y-x+1];//分區間大小
int mid=(a[dp[x][k]]>=a[dp[y-(1<<k)+1][k]]?
dp[x][k]:dp[y-(1<<k)+1][k]);
if(mid-x<y-mid)//最大值在左
{
for(int i=x; i<=mid; i++)
{
int pos=lower_bound(sum+mid,sum+y+1,sum[i-1]+2LL*a[mid])-sum;
ans+=y-pos+1;
}
}
else
{
for(int i=mid; i<=y; i++)
{
int pos=lower_bound(sum1+n-mid+1,sum1+n-x+2,sum1[n-i]+2LL*a[mid])-sum1;
ans+=n+1-x-pos+1;
}
}
solve(x,mid-1);
solve(mid+1,y);
}
int main()
{
lg[0]=-1;
for(int i=1; i<N; i++)
{
lg[i]=lg[i>>1]+1;
}
int t;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int i=1; i<=n; i++)
sum1[i]=sum1[i-1]+a[n-i+1];
RMQ();
solve(1,n);
printf("%lld\n",ans);
}
return 0;
}
19hdu多校-10 6701 Make Rounddog Happy
題意:
max(al,al+1,…,ar)−(r−l+1)≤k.
思路:
還是區間分治。
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <iterator>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e6+10;
int a[N],lg[N],dp[N][20],n,m;
int A[N],B[N],vis[N];ll ans;
void RMQ()
{
for(int i=1; i<=n; i++)
dp[i][0]=i;///裏面存的下標
for(int i=1; (1<<i)<=n; i++)
{
int d=(1<<i);
for(int j=1; j+d-1<=n; j++)
{
dp[j][i]=a[dp[j][i-1]]>=a[dp[j+(1<<(i-1))][i-1]]?
dp[j][i-1]:dp[j+(1<<(i-1))][i-1];
}
}
}
int get(int L,int R)
{
int k=lg[R-L+1];
return a[dp[L][k]]>=a[dp[R-(1<<k)+1][k]]?dp[L][k]:dp[R-(1<<k)+1][k];
}
void solve(int l,int r)
{
if(r<l)
return;
int k=lg[r-l+1];///分區間大小
int mid=(a[dp[l][k]]>=a[dp[r-(1<<k)+1][k]]?
dp[l][k]:dp[r-(1<<k)+1][k]);
int len=a[mid]-m;
if(mid-l<r-mid)
{
for(int i=mid; i>=l; i--)
{
int L=max(mid,i+len-1);
int R=min(B[i],r);
if(R>=L)
ans+=R-L+1;
}
}
else
{
for(int i=mid; i<=r; i++)
{
int L=max(l,A[i]);
int R=min(i-len+1,mid);
if(R>=L)
ans+=R-L+1;
}
}
solve(l,mid-1);
solve(mid+1,r);
}
int main()
{
lg[0]=-1;
for(int i=1; i<N; i++)
{
lg[i]=lg[i>>1]+1;
}
int t;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
RMQ();
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=n;i++){
A[i]=vis[a[i]]+1;
vis[a[i]]=i;
}
for(int i=2;i<=n;i++) A[i]=max(A[i-1],A[i]);///防止出現1 2 3 2 1這種情況
for(int i=n;i>=1;i--) vis[i]=n+1;
for(int i=n;i>=1;i--){
B[i]=vis[a[i]]-1;
vis[a[i]]=i;
}
for(int i=n-1;i>=1;i--) B[i]=min(B[i+1],B[i]);
solve(1,n);
printf("%lld\n",ans);
}
return 0;
}