zoukankan      html  css  js  c++  java
  • BZOJ 4299: Codechef FRBSUM

    BZOJ 4299: Codechef FRBSUM

    标签(空格分隔): OI-BZOJ OI-可持久化线段树


    Time Limit: 10 Sec
    Memory Limit: 128 MB


    Description

    数集S的ForbiddenSum定义为无法用S的某个子集(可以为空)的和表示的最小的非负整数。
    例如,S={1,1,3,7},则它的子集和中包含0(S’=∅),1(S’={1}),2(S’={1,1}),3(S’={3}),4(S’={1,3}),5(S' = {1, 1, 3}),但是它无法得到6。因此S的ForbiddenSum为6。
    给定一个序列A,你的任务是回答该数列的一些子区间所形成的数集的ForbiddenSum是多少。
    Input

    输入数据的第一行包含一个整数N,表示序列的长度。
    接下来一行包含N个数,表示给定的序列A(从1标号)。
    接下来一行包含一个整数M,表示询问的组数。
    接下来M行,每行一对整数,表示一组询问。
    Output

    对于每组询问,输出一行表示对应的答案。
    Sample Input

    5

    1 2 4 9 10

    5

    1 1

    1 2

    1 3

    1 4

    1 5
    Sample Output

    2

    4

    8

    8

    8
    HINT

    对于100%的数据,1≤N,M≤100000,1≤A_i≤109,1≤A_1+A_2+…+A_N≤109。


    Solution####

    与4408一样

    求神秘数:设[1,x]都可以被表示,那么加入一个数字a可以发现[1+a,x+a]可以被表示,x+1不能被表示的条件是((sumlimits_{a_i<=x+1}a_i)<x+1)迭代即可,会被fibonacci数列卡到极限,(O(nlog_2n*40))


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int read()
    {
    	int s=0,f=1;char ch=getchar();
    	while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    	while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    	return s*f;
    }
    struct tree
    {
    	int s,w[2];
    }t[3000005];
    int n,w,c,np;
    int s[100005],ls[100005],st[100005];
    void plu(int x,int s,int c,const int num)
    {
    	int now=++np;t[now]=t[x];
    	if(c==-1){t[now].s+=num;return;}
    	int p=((s>>c)&1);
    	plu(t[now].w[p],s-(p<<c),c-1,num);
    	t[now].w[p]=now+1;
    	t[now].s=t[t[now].w[0]].s+t[t[now].w[1]].s;
    }
    int countt(const int x,const int s,const int c)
    {
    	if(c==-1)return 0;
    	int p=((s>>c)&1);
    	return countt(t[x].w[p],s-(p<<c),c-1)+(p?t[t[x].w[0]].s:0);
    }
    int count(int x,int y,int s,int c)
    {
    	return countt(x,s,c)-countt(y,s,c);
    }
    int ef(int ans)
    {
    	int l=1,r=n+1;ls[r]=2000000000;
    	while(l^r)
    	  {int mid=l+r>>1;
    	   if(ls[mid]>ans)
    	     r=mid;
    	   else
    	     l=mid+1;
    	  }
    	return l;
    }
    int main()
    {
    	//freopen("mystic.in","r",stdin);
    	//freopen("mystic.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	   s[i]=ls[i]=read();
    	sort(&ls[1],&ls[n+1]);
    	for(int i=1;i<=n;i++)
    	   s[i]=lower_bound(&ls[1],&ls[n+1],s[i])-ls;
    	for(w=1,c=0;w<=n;w*=2,c++);np=1;st[0]=1;
    	for(int i=1;i<=n;i++)
    	   st[i]=np+1,
    	   plu(st[i-1],s[i],c-1,ls[s[i]]);
    	for(int m=read();m--;)
    	   {
    			int l=read(),r=read();
    			int ans=1,ss=0;
    			while((ss=count(st[r],st[l-1],ef(ans),c-1))>=ans)
    			  ans=ss+1;
    			printf("%d
    ",ans);
    	   }
    	//fclose(stdin);
    	//fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    proc文件系统
    sysfs文件系统
    linux 下 进程和线程的区别
    Linux内核中常见内存分配函数
    内核空间与用户空间的通信方式
    DoDataExchange函数,UpdateData(TRUE)和UpdateData(FALSE)的区别
    C# 获取文件路径
    C# WinForm 中 MessageBox的使用详解
    C#对于文件操作
    线程间操作无效: 从不是创建控件的线程访问它。
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5242101.html
Copyright © 2011-2022 走看看