题目大意:
给你一个数字序列
就是每次查询一个区间问你这个区间中的数不能组合成的数的最小是多少?
解题思路:
1.首先我们知道假设这个区间里面没有1那么
a
n
s
=
1
ans=1
ans=1
2.对于区间里面的数
b
1
<
b
2
<
b
3
.
.
<
b
n
b_1<b_2<b_3..<b_n
b1<b2<b3..<bn
s
u
m
[
i
]
=
∑
i
=
1
n
b
[
i
]
sum[i]=\sum_{i=1}^nb[i]
sum[i]=∑i=1nb[i]
3.假如区间里面前
i
i
i个数
(
b
1
,
2
,
3...
i
)
(b_{1,2,3...i})
(b1,2,3...i)可以表示
[
1
,
x
]
[1,x]
[1,x]里面所有的数,那么接下来我们据要看是否可以表示出
x
+
1
x+1
x+1,假如说
b
i
+
1
>
x
+
1
b_{i+1}>x+1
bi+1>x+1的话那么无论它怎么和前面的数组合都是大过
x
+
1
x+1
x+1那么答案就是
x
+
1
x+1
x+1,假如
b
i
+
1
<
x
+
1
b_{i+1}<x+1
bi+1<x+1因为前面是
∈
[
1
,
x
]
那
么
就
有
x
+
1
−
b
i
+
1
这
个
数
在
里
面
就
一
定
可
以
凑
出
x
+
1
\in[1,x]那么就有x+1-b_{i+1}这个数在里面就一定可以凑出x+1
∈[1,x]那么就有x+1−bi+1这个数在里面就一定可以凑出x+1,那么对于是否可以凑出
x
+
1
x+1
x+1实际上就是在
所
有
小
于
x
+
1
的
b
i
之
和
是
否
超
过
b
i
所有小于x+1的b_i之和是否超过b_i
所有小于x+1的bi之和是否超过bi
4.那么我们就可以暴力枚举 那个
x
+
1
x+1
x+1,
假
如
已
经
有
[
1
,
x
]
再
来
个
x
+
1
就
可
以
表
示
的
数
会
变
成
[
1
,
2
∗
x
+
1
]
这
个
增
长
接
近
指
数
的
那
么
就
是
近
乎
l
o
g
级
别
的
枚
举
是
可
以
接
受
假如已经有[1,x]再来个x+1就可以表示的数会变成[1,2*x+1]这个增长接近指数的那么就是近乎log级别的枚举是可以接受
假如已经有[1,x]再来个x+1就可以表示的数会变成[1,2∗x+1]这个增长接近指数的那么就是近乎log级别的枚举是可以接受。
5.对于询问某段区间里面小于某个值的和我们可以用
主
席
树
主席树
主席树因为这个具有前缀和性质。
#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
struct BIT {
int lson, rson;
ll sum;
}tr[maxn * 40];
int idx;
vector<ll> lis;
int n, m;
ll num[maxn];
int root[maxn];
int getid(ll x) {
if(x >= lis[lis.size()-1]) return lis.size();
return lower_bound(lis.begin(),lis.end(),x)-lis.begin();
}
inline void insert(int &rt, int l, int r, int pos, int pre, int val) {
rt = ++ idx;
tr[rt] = tr[pre];
if(l == r) {
tr[rt].sum += val;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) insert(tr[rt].lson,l,mid,pos,tr[pre].lson, val);
else insert(tr[rt].rson,mid+1,r,pos,tr[pre].rson, val);
tr[rt].sum = tr[tr[rt].lson].sum + tr[tr[rt].rson].sum;
}
inline ll ask(int pos, int l, int r, int ltree, int rtree) {
if(l == r) {
return tr[rtree].sum - tr[ltree].sum;
}
int mid = (l + r) >> 1;
if(pos <= mid) return ask(pos,l,mid,tr[ltree].lson,tr[rtree].lson);
else return ask(pos,mid+1,r,tr[ltree].rson,tr[rtree].rson) + tr[tr[rtree].lson].sum - tr[tr[ltree].lson].sum;
}
int main() {
//.........................
lis.push_back(-INF);
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; ++ i) {
scanf("%lld",&num[i]);
lis.push_back(num[i]);
}
sort(lis.begin(),lis.end());
lis.erase(unique(lis.begin(),lis.end()),lis.end());
for(int i = 1; i <= n; ++ i)
insert(root[i],1,n,getid(num[i]),root[i-1],num[i]);
ll ans = 0;
while(m --) {
int l , r;
scanf("%d %d",&l,&r);
l = (l+ans)%n+1;
r = (r+ans)%n+1;//坑点
if(l > r) swap(l,r);
ans = 0;
while(1) {
int p = getid(ans+1);//注意离散化之后求比ans+1小的数的下标
if(lis[p] > ans + 1) p --;//如果不是向下取整
if(!p) break
ll t = ask(p,1,n,root[l-1],root[r]);
if(t == ans) break;
ans = t;
}
printf("%lld\n",ans+1);
ans += 1;
}
return 0;
}
/*
5 5
1 4 2 1 6
1 3
2 1
2 4
1 4
3 4
*/