2019牛客暑期多校训练营(第四场)

B xor

题意
给定n个集合,编号为1-n,有m次询问,每次询问L,R,X,表示L-R的集合是否都能用子集异或和表示X
思路
学到了线性基的新操作,求两个基的交集。对于任意两个基来说,如果他们的交集构成的基,能够表示X,那么这两个基一定也能表示X。因此需要通过线段树来维护区间交集,剩下的就很简单了。之前在区间查询的时候有点智障的又求了一边交集,其实并不需要,在查询的时候直接find就能得到结果了。

C sequence

题意
m a x 1 ≤ l ≤ r ≤ n { m i n ( a [ l … r ] ) × s u m ( b [ l … r ] ) } max_{1\le l\le r\le n}\{min(a [l…r] )×sum(b [l…r])\} max1lrn{min(a[lr])×sum(b[lr])}
思路
首先通过单调队列或者单调栈可以求出a[i]作为最小值所影响的范围,再对b求前缀和以后用线段树维护最大和最小值。
假设L,R是a[i]作为最小值影响的区间,则有
当a[i]为正数时
a n s = m a x ( a [ i ] ∗ ( M A X ( i , R ) − M I N ( L , i − 1 ) ) ) ans=max(a[i]*(MAX(i,R)-MIN(L,i-1))) ans=max(a[i](MAX(i,R)MIN(L,i1)))
当a[i]为负数时
a n s = m a x ( a [ i ] ∗ ( M I N ( i , R ) − M A X ( L , i − 1 ) ) ) ans=max(a[i]*(MIN(i,R)-MAX(L,i-1))) ans=max(a[i](MIN(i,R)MAX(L,i1)))
具体看代码才能懂,这题真的是究极卡常数,T了无数发才过。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>

using namespace std;
typedef long long ll;

const int maxn = 3e6+10;
const int mod = 1e9+7;
const ll inf=1e18-1;


#define lson node<<1
#define rson node<<1|1
ll treemin[4*maxn]; // 线段树
ll treemax[4*maxn];
ll a[maxn],b[maxn];
int la[maxn];
int ra[maxn];
  int n;
struct node{
    ll v;
    int pos;
}dque[maxn];
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
// 创建线段树
void build(int node,int l,int r){
	if(l == r){
        treemin[node]=b[l];
        treemax[node]=b[l];
		return;
	}
	int mid = (l+r)/2;
	build(lson,l,mid);
	build(rson,mid+1,r);
	treemin[node] = min(treemin[lson] , treemin[rson]);
	treemax[node] = max(treemax[lson] , treemax[rson]);
}
// 区间查找
ll querymax(int node,int l,int r,int L,int R){
	if(l >= L && r <= R)
    {
        return treemax[node];
    }
	int mid = (l+r) / 2;
	ll sum;

	    sum = -inf;
        if(mid >= L) sum= max(sum,querymax(lson,l,mid,L,R)) ;
        if(mid < R) sum= max (sum,querymax(rson,mid+1,r,L,R));

	return sum;
}


ll querymin(int node,int l,int r,int L,int R){
	if(l >= L && r <= R)
    {
        return treemin[node];
    }
	int mid = (l+r) / 2;
	ll sum;

        sum = inf;
        if(mid >= L) sum= min(sum,querymin(lson,l,mid,L,R)) ;
        if(mid < R) sum= min(sum,querymin(rson,mid+1,r,L,R));
	return sum;
}

void init()
{
    int l=0,r=0;
    dque[0].v=-inf;
    a[n+1]=-inf;
    for(int i=1;i<=n+1;i++)
    {
        while(a[i]<dque[r].v)
        {
            ra[dque[r--].pos]=i-1;
        }
        dque[++r].v=a[i];
        dque[r].pos=i;
    }
    l=0,r=0;
    dque[0].v=-inf;
    a[0]=-inf;
    for(int i=n;i>=0;i--)
    {

        while(a[i]<dque[r].v)
        {
            la[dque[r--].pos]=i+1;
        }
        dque[++r].v=a[i];
        dque[r].pos=i;

    }
    build(1,0,n);

}


int main(){

    n=read();
    for(int i=1;i<=n;i++)
    {
       a[i]=read();
    }
    for(int i=1;i<=n;i++)
    {
        b[i]=read();
         b[i]+=b[i-1];
    }
    init();
    ll ans=-inf;
    for(int i=1;i<=n;i++)
    {
        int l=la[i];
        int r=ra[i];
        if(a[i]>0)
        ans=max(ans,(querymax(1,0,n,i,r)-querymin(1,0,n,l-1,i-1))*a[i]);
        else
        ans=max(ans,(querymin(1,0,n,i,r)-querymax(1,0,n,l-1,i-1))*a[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值