牛客训练(BIT+高精度)

又是这类用BIT辅助计数的题。。

这个显然满足要求的区间比不满足的要多太多,所以变成求不满足的。。。

然后要先求总方案数,为

\sum_{l_2=1}^{n}\sum_{r_2=l_2}^{n}l_2(l_2+1)/2=\sum_{l_2=1}^{n}l_2(l_2+1)(n-l_2+1)/2

这个不是很想在化了,反正O(n)求也可以的。。

然后求不满足的。。这里已经有4个端点,如果再枚举端点什么的显然很不明智。。因此应该从区间的性质入手,所以要枚举最值。。

枚举[l2,r2]的max,从大到小枚举,设此时的位置为i,可以发现,能构成区间2的个数有(i-pre[i])*(next[i]-i),其中pre和next代表比a[i]大且里i最近的左边的数和右边的数。。此时有发现,其实区间1已经被pre[i]分隔开了,因为pre[i]后面的数区间1是绝对不能取的(否则区间1的min会小于区间2的max),然后现在就是算区间1的个数了,可以发现区间1必须完全由之前被枚举过的数构成,那么只要用BIT维护一下i之前的这些区间块的个数和大小就可以了。。

这个要如何维护呢?每次枚举的时候判断一下左右是否被枚举过,如果有直接合并,把区间1的方案数修改一下即可。。

然后pre是用BIT算的,貌似有点浪费。。

另外总方案数会爆ll,之前学杜教的小高精终于能派上用场了。。

 

 

 

/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<stdlib.h>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y)/2
#define NM 1000005 
#define nm 40005
#define pi 3.1415926535897931
const ll inf=1e16;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar() ;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}






int n,b[NM],nxt[NM],f[NM],sz[NM];
int c[NM];
ll a[NM];
__int128 ans;


void _add(int x,int t){for(;x<=n;x+=lowbit(x))c[x]=max(c[x],t);}
int _sum(int x,int s=0){for(;x;x-=lowbit(x))s=max(s,c[x]);return s;}
void add(int x,ll t){for(;x<=n;x+=lowbit(x))a[x]+=t;}
ll sum(int x,ll s=0){for(;x;x-=lowbit(x))s+=a[x];return s;}


int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
ll fun(ll n){return n*(n+1)/2;}

int main(){
    n=read();inc(i,1,n)b[read()]=i;
    inc(i,1,n+1)f[i]=i;
    nxt[0]=n+1;
    inc(i,1,n)ans+=(ll)i*(i-1)/2*(n-i+1);
    dec(k,n,1){
	int i=b[k];
	int l=_sum(i);int r=nxt[l];
	nxt[l]=i;nxt[i]=r;_add(i,i);
       	__int128 s=(ll)(i-l)*(r-i);
	s*=sum(l);ans-=s;
	sz[i]=1;
	if(l==i-1){
	    int x=find(l);
	    sz[i]+=sz[x];f[x]=i;if(sz[x])add(x,-fun(sz[x]));
	}
	if(r==i+1){
	    int x=find(r);
	    sz[i]+=sz[x];f[x]=i;if(sz[x])add(x,-fun(sz[x]));
	}
	add(i,fun(sz[i]));
    }
    ll tmp;
    if(ans<inf)printf("%lld\n",tmp=ans);
    else{
	tmp=ans/inf;ll t=ans%inf;
	printf("%lld%016lld\n",tmp,t);
    }
    return 0;
}

 

 

 

 

 

链接:https://www.nowcoder.com/acm/contest/203/E
来源:牛客网
 

Trophies

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

蒜头的家里有一张长长的桌子,桌子上有n个奖杯排成一排。我们用xi表示第i个奖杯的高度。奖杯的高度两两不同,为了方便,我们保证x是一个的排列。

由于蒜头的桌子已经放不下新的奖杯了,他打算将一些奖杯送给修修和栋栋。具体来说,他打算选择四个参数l1,r1,l2,r2 (1 ≤ l1 ≤ r1 < l2 ≤ r2 ≤ n),

然后将区间[l1,r1]中的奖杯送给修修,将区间[l2,r2]中的奖杯送给栋栋。
修修不希望他拿到的奖杯中最矮的一个比栋栋拿到的奖杯中最高的一个还要高,因此他想知道有多少种方案满足

输入描述:

第一行一个整数n (1 ≤ n ≤ 106),第二行n个整数 (1 ≤ xi ≤ n)。

输出描述:

输出一行一个整数表示方案数。

示例1

输入

复制

5
1 4 3 5 2

输出

复制

28
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值