zoukankan      html  css  js  c++  java
  • FJOI2016 神秘数

    题目大意

    给定长为$N$一个序列,每次询问一个区间,求最小的不能表示为由区间内若干个(可以是$0$个)数的和的非负整数。

    考虑一个可重集合$S$,设抽取$S$中若干个数相加无法得到的最小非负整数为$Ans_S$

    显然$Ans_{emptyset}=1$

    当加入一个元素$x$时

    当$x>Ans_S$时,原先的$Ans_S$仍然无法凑出来,所以答案不变

    当$xleq Ans_S$时,原先的$0,1...Ans_S-1$可表示为$x,x+1...Ans_S-1+x$由于$xleq Ans_S-1$

    所以$S$加入$x$后得到的$K$一可以表示$0,1...Ans_S+x-1$,而$Ans_S+x$仍然无法凑出来

    所以$Ans_K=Ans_S+x$

    但是这样直接做还是会$TLE$,因为每次询问得把区间扫一遍。

    我们想一个很暴力的优化。

    设当前答案为$ans$,你已经加上了区间内小于等于$last$的数的和。

    由于答案已经达到了$ans$,我们求出$sum=$区间内满足$last<xleq ans$的所有$x$的和。

    若$sum=0$,则答案已经不再影响,直接停止就好,否则我们令$last=ans,ans=ans+sum$即可。

    初始时$last=0,ans=1$。

    这看起来很暴力,但是其中对于所有的若$sum>0$,则一定有$sum>last$,所以每两次操作$last$至少扩大一倍,而所有数的总和又是固定的,所以对于每一次询问$ans$只会进行$log$级别次数的增加。

    区间求一定值域内的和,用可持久化线段树维护即可。

    复杂度$O(Nlog(sum A_i)+Mlog^2(sum A_i))$

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 120000
    #define mid ((l+r)>>1)
    #define MAXN 1000000002
    using namespace std;
    int read(){
    	int nm=0,fh=1; char cw=getchar();
    	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    int n,m,sum[M*32],L[M*32],R[M*32],rt[M],cnt;
    void write(int x){if(x>9) write(x/10); putchar(x-(x/10)*10+'0');}
    void ins(int &x,int pre,int l,int r,int pos){
    	x=++cnt,L[x]=L[pre],R[x]=R[pre];
    	sum[x]=sum[pre]+pos; if(l==r) return;
    	if(pos<=mid) ins(L[x],L[pre],l,mid,pos);
    	else ins(R[x],R[pre],mid+1,r,pos);
    }
    int qry(int now,int pre,int l,int r,int ls,int rs){
    	if(sum[now]==sum[pre]||r<ls||rs<l) return 0;
    	if(ls<=l&&r<=rs) return sum[now]-sum[pre];
    	return qry(L[now],L[pre],l,mid,ls,rs)+qry(R[now],R[pre],mid+1,r,ls,rs);
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++) m=read(),ins(rt[i],rt[i-1],1,MAXN,m);
    	for(int T=read(),last=0,ans=1;T;T--,last=0,ans=1){
    		int ls=read()-1,rs=read(),now=0;
    		while(true){
    			now=qry(rt[rs],rt[ls],1,MAXN,last+1,ans);
    			if(!now) break; last=ans,ans+=now;
    		} write(ans),putchar('
    ');
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Android开发之Sqlite的使用
    ZOJ 3607 Lazier Salesgirl
    ZOJ 3769 Diablo III
    ZOJ 2856 Happy Life
    Ural 1119 Metro
    Ural 1146 Maximum Sum
    HDU 1003 Max Sum
    HDU 1160 FatMouse's Speed
    Ural 1073 Square Country
    Ural 1260 Nudnik Photographer
  • 原文地址:https://www.cnblogs.com/OYJason/p/9743208.html
Copyright © 2011-2022 走看看