zoukankan      html  css  js  c++  java
  • 神秘题目3

    神秘题目

    题目描述

    给定整数序列 (a_1,...,a_n)

    (m) 次询问,每次给定 (L,R) 求一个最小的非负整数 (x)

    满足对于任意的 (b_iin{0,1}) ,都满足 (x≠sumlimits_{i=L}^R{a_i imes b_i})

    输入格式

    第一行 2 个整数 (n),(m)

    接下来 1 行 (n) 个整数表示 (a_i)

    接下来 (m) 行,每行第一个整数 (opt)

    • (opt=1) ,接下来 2 个整数 (k,y) 表示令 (a_k=y)
    • (opt=2) ,接下来 2 个整数 (L,R) 表示一次查询操作

    输出格式

    若干行每行一个整数,对应一次查询操作的答案。

    样例输入

    5 5
    3 4 2 1 9
    2 1 5
    1 1 2
    2 1 3
    1 2 8
    2 2 4
    

    样例输出

    20
    1
    4
    

    数据范围与约定

    对于 (10\%) 的数据 (n,mle 10)

    对于 (30\%) 的数据 (n,mle 2000)(xle2000)

    另有 (20\%) 的数据 (L=1,R=n,m=3)

    对于 (100\%) 的数据 (n,mle 4 imes 10^4 ,1le a_ile10^9)

    时间限制:(1s)

    空间限制:(256MB)

    提示: (4 imes 10^4=200^2) , (nsqrt{n})

    题解

    10分做法

    爆搜啥的都行

    30分做法

    注意到答案 (x) 不超过 (2000),可以考虑背包

    LL ask(int L,int R)
    {
    	memset(vis,0,sizeof vis);
    	vis[0]=1;
    	for(int i=L;i<=R;i++)
    	for(int j=2000;j>=a[i];j--)
    		vis[j]|=vis[j-a[i]];
    	for(int i=1;i<=2000;i++)
    	if(!vis[i])return i;
    	return 0;
    }
    

    另外20分

    其实就是送的,(m) 只有 (3)

    每次询问时,将 (a_i) 从小到大排序。设一个累加器 (sum=0),从小到大考虑每一个值,如果 (a_ile sum+1) ,那么将 (sum) 加上 (a_i) 。否则 (sum+1) 就是答案。

    原理:(sum) 其实代表 ([0,sum]) 的值都可以拼出来,如果 (a_ile sum+1) 那么 ([0,sum+a_i]) 也都可以拼出来。

    这一档分对正解有提示作用。

    满分做法

    上一档分的瓶颈在于排序和累加,这两项其实不可以通过分块优化(或者是我不会)

    一个显而易见的结论

    如果一组 $a_ i $ 使 ([0,2^k]) 都可以拼出来并且 (sum a_i le 2^{k+1}) ,只要再多一个 (pin [2^k+1,2^{k+1}])(ple sum a_i +1) ,那么 ([0,2^{k+1}]) 都可以拼出来。

    有了这个结论相信大家都会做了。可以用线段树维护 $a_l .. a_r $ 中所有大小在 ([2^k,2^{k+1}]) 范围内的 $a_i $ 和,和最小值。

    那么扫描每一段 ([2^k,2^{k+1}]) ,就行了。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int inf=1<<30;
    int n,m,a[40010],mi[40]={0,1},Lbel,Nbel;
    LL sum[31],ans;int minn[31];
    struct SegmentTree
    {int l,r,min[31];LL data[31];}st[160010];
    inline int read()
    {
    	int x=0;bool w=0;char ch=0;
    	while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return w?-x:x;
    }
    inline int getbel(int x)
    {
    	if(x==1)return 1;
    	int temp=1,l=1,r=30,mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(x>=mi[mid])temp=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return temp;
    }
    void build(int p,int l,int r)
    {
    	st[p].l=l;st[p].r=r;
    	if(l==r){
    		int Bel=getbel(a[l]);
    		for(int i=1;i<=30;i++)st[p].min[i]=inf;
    		st[p].data[Bel]=st[p].min[Bel]=a[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);
    	build(p<<1|1,mid+1,r);
    	for(int i=1;i<=30;i++){
    		st[p].data[i]=st[p<<1].data[i]+st[p<<1|1].data[i];
    		st[p].min[i]=min(st[p<<1].min[i],st[p<<1|1].min[i]);
    	}
    }
    void change(int p,int pos,int k)
    {
    	if(st[p].l==st[p].r){
    		st[p].data[Lbel]=0;st[p].min[Lbel]=inf;
    		st[p].data[Nbel]=st[p].min[Nbel]=k;
    		return;
    	}
    	int mid=(st[p].l+st[p].r)>>1;
    	if(pos<=mid)change(p<<1,pos,k);
    	else change(p<<1|1,pos,k);
    	st[p].data[Lbel]=st[p<<1].data[Lbel]+st[p<<1|1].data[Lbel];
    	st[p].min[Lbel]=min(st[p<<1].min[Lbel],st[p<<1|1].min[Lbel]);
    	st[p].data[Nbel]=st[p<<1].data[Nbel]+st[p<<1|1].data[Nbel];
    	st[p].min[Nbel]=min(st[p<<1].min[Nbel],st[p<<1|1].min[Nbel]);
    }
    void calc(int p,int l,int r)
    {
    	if(l<=st[p].l&&st[p].r<=r){
    		for(int i=1;i<=30;i++){
    			minn[i]=min(minn[i],st[p].min[i]);
    			sum[i]+=st[p].data[i];
    		}
    		return;
    	}
    	int mid=(st[p].l+st[p].r)>>1;
    	if(l<=mid)calc(p<<1,l,r);
    	if(mid<r)calc(p<<1|1,l,r);
    }
    LL ask(int l,int r)
    {
    	memset(minn,0x3f,sizeof minn);
    	memset(sum,0,sizeof sum);
    	calc(1,l,r);
    	ans=sum[1];
    	for(int i=2;i<=30;i++)
    	if(ans+1>=minn[i])ans+=sum[i];
    	return ans+1;
    }
    int main()
    {
    	freopen("min.in","r",stdin);
    	freopen("min.out","w",stdout);
    	for(int i=2;i<=30;i++)mi[i]=mi[i-1]*2;
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	build(1,1,n);
    	while(m--){
    		int opt=read(),l=read(),r=read();
    		if(opt&1){
    			Lbel=getbel(a[l]);Nbel=getbel(a[l]=r);
    			change(1,l,r);
    		}else printf("%lld
    ",ask(l,r));
    	}
    }
    
  • 相关阅读:
    c# 键值数据保存XML文件
    c# 封装 Request操作类
    c# 获取客户端IP
    c#封装DBHelper类
    c# Cache 使用实例
    c#cookie读取写入操作
    c# Session写入读取操作
    ABAP-HTTP支持
    WDA-文档-基础篇/进阶篇/讨论篇
    UI5-文档-4.38-Accessibility
  • 原文地址:https://www.cnblogs.com/zYzYzYzYz/p/14449095.html
Copyright © 2011-2022 走看看