神秘数

来源:互联网 发布:最好的网络验证 编辑:程序博客网 时间:2024/04/19 23:42

神秘数

时间限制: 1 Sec 内存限制: 256 MB
题目描述
一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
1 = 1
2 = 1+1
3 = 1+1+1
4 = 4
5 = 4+1
6 = 4+1+1
7 = 4+1+1+1
8无法表示为集合S的子集的和,故集合S的神秘数为8。
现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间l,r,求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘

输入
第一行一个整数n,表示数字个数。
第二行n个整数,从1编号。
第三行一个整数m,表示询问个数。
以下m行,每行一对整数l,r,表示一个询问。

输出
对于每个询问,输出一行对应的答案。

样例输入
5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5

样例输出
2
4
8
8
8

【数据范围】
对于10%的数据点,n,m <= 10
对于30%的数据点,n,m <= 1000
对于60%的数据点,n,m <= 50000
对于100%的数据点,n,m <= 100000,∑a[i] <= 109

来源
FJOI2016

题解

写在前面:就是这道题害我省选爆零,直接退役。
进入正题:
考虑一段数列,如何计算它的神秘数?
将其排序,若sum[i-1]>s[i]+1,那么神秘数即为sum[i-1]。
对于一组询问,每次暴力更新区间内>=sum+1的数,当出现斐波那契数列时达到上界。
用一棵主席树维护区间和。
注意细节,记得对拍,不然就要像我一样爆零退役了。

代码

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> #define N 100010#define inf 2100000000using namespace std;int n,m,tot,s[N],id[N],num[N],rt[N],cnt;struct node{int lc,rc,sum;}t[N*18];bool cmp(const int &a,const int &b){return s[a]<s[b];}class functional_seg_tree{  public:  void modify(int &x,int pre,int l,int r,int des,int val)  {    x=++cnt;t[x]=t[pre];t[x].sum+=val;    if(l==r)return;    int mid=l+r>>1;    if(des<=mid)modify(t[x].lc,t[pre].lc,l,mid,des,val);    else modify(t[x].rc,t[pre].rc,mid+1,r,des,val);  }  int qry(int x,int l,int r,int ql,int qr)  {    if(ql<=l&&r<=qr)return t[x].sum;    int mid=l+r>>1,res=0;    if(ql<=mid)res+=qry(t[x].lc,l,mid,ql,qr);    if(qr>mid)res+=qry(t[x].rc,mid+1,r,ql,qr);    return res;  }}T;int main(){  int a,b;  scanf("%d",&n);  for(int i=1;i<=n;i++)scanf("%d",&s[i]),id[i]=i;  sort(id+1,id+n+1,cmp);  for(int i=1;i<=n;i++)  {    num[++tot]=s[id[i]];    T.modify(rt[tot],rt[tot-1],1,n,id[i],s[id[i]]);    while(s[id[i]]==s[id[i+1]])      i++,T.modify(rt[tot],rt[tot],1,n,id[i],s[id[i]]);  }  scanf("%d",&m);  while(m--)  {    scanf("%d%d",&a,&b);    int ans=0,pre=0;    while(1)    {      int l=1,r=tot,pos=0;      while(r-l>1)      {        int mid=l+r>>1;        if(num[mid]<=ans+1)l=mid;        else r=mid-1;         }      pos=num[r]<=ans+1?pos=r:l;      if(pos==pre)break;      ans=T.qry(rt[pre=pos],1,n,a,b);    }    printf("%d\n",ans+1);  }  return 0;}
0 0
原创粉丝点击