博主的 BiBi 时间
考场上做了好久这玩意儿。好不容易想出来 \(a_i\) 是 \(2\) 的非负整数次方的做法,不会敲。
嘤嘤嘤。
\(\text{Solution}\)
\(10\text{pts}\)
考场上真的有人和我一起打弱智十分吗?
思路就是把所有情况枚举出来。考场上非常智障竟然用了个 \(\text{map}\) 存不知道什么的东西。其实只要大法师就行了。
#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,m,a[maxn],tp;
ll q[5000005];
map <ll,int> mp;
int main() {
int l,r,tmp; bool flag;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) {
scanf("%d %d",&l,&r);
mp.clear(); mp.insert(make_pair(0,1));
q[tp=1]=0;
for(int j=l;j<=r;++j) {
tmp=tp;
for(int k=1;k<=tmp;++k)
if(!mp.count(q[k]+a[j]))
mp.insert(make_pair(q[k]+a[j],1)),
q[++tp]=q[k]+a[j];
}
sort(q+1,q+tp+1); flag=0;
for(int i=1;i<=tp;++i) if(q[i]^(i-1)) {printf("%d\n",i-1); flag=1; break;}
if(!flag) printf("%d\n",tp);
}
return 0;
}
\(\text{20pts}\)
\(\mathcal O(n^2\log n)\)。
正解就是从这个而来的。考虑将原数组排序然后依次加入,每次选小于等于当前 \(sum+1\) 的值加进 \(sum\) 一直加到加不了。
考虑先开始的 \(sum=0\) 即 \([0,sum]\) 之间所有数都可以被表示,此时我们可以加入一个新的数,可以使得 \([0+k,sum+k]\) 的所有数都可以被表示。不过我们要找到从 \(0\) 开始连续能被表示的区间,所以暂时将新扩展的区间的 \(l\) 至少要小于等于 \(sum+1\) 吧。所以我们选择的下一个数的区间必须在 \([0,sum+1]\) 之间。
依次扩展后答案显然就是 \(sum+1\)。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,m,a[maxn],tp,b[maxn];
int main() {
int l,r; ll tmp;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) {
scanf("%d %d",&l,&r);
for(int j=l;j<=r;++j) b[j-l+1]=a[j];
sort(b+1,b+r-l+2); tmp=0;
for(int j=1;j<=r-l+1;++j) if(tmp+1>=b[j]) tmp+=b[j];
printf("%lld\n",tmp+1);
}
return 0;
}
\(\text{100pts}\)
再接再厉!
咱们接着上文的思路,其实问题已经转化为求小于等于一个数的数的和,还要可持久化(支持两个版本相减),可以用可持久化 \(\text{Trie}\) 树。
可以证明 \(ans\) 的增长只有 \(\log(1e9)\)。考虑上次的 \(ans\) 为 \(lastAns\),那么这次选的数一定大于 \(lastAns\),不然会和上次选重,所以每次必须乘 \(2\)。
有一个应该注意的点:将 \(x\) 二进制分解时因为原数组范围在 \(2^{30}\) 之间,但是新算出来的 \(ans\) 会爆,不能直接分解,应该转化为 \(2^{31}-1\) 即 \(0-30\) 为全为 \(1\)。不然会有本来很大,但由于只算了 \(31\) 位算小的情况。
总时间复杂度 \(\mathcal O(n\log^2(1e9))\)。
#include <cstdio>
#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
typedef long long ll;
const int maxn=1e5+5;
int n,m,bin[33],siz,rt[maxn];
struct Tree {int lson,rson; ll val;} t[maxn*35];
void div(ll x) {
if(x>=(1ll<<31)-1) x=(1ll<<31)-1;
rep(i,0,30) bin[i]=((x>>i)&1);
}
void modify(int &o,int pre,int k,int dep) {
t[o=++siz]=t[pre];
if(dep<0) {t[o].val+=k; return;}
if(bin[dep]) modify(t[o].rson,t[pre].rson,k,dep-1);
else modify(t[o].lson,t[pre].lson,k,dep-1);
t[o].val=t[t[o].lson].val+t[t[o].rson].val;
}
ll query(int o,int dep) {
if(dep<0||o==0) return t[o].val;
if(bin[dep]) return t[t[o].lson].val+query(t[o].rson,dep-1);
return query(t[o].lson,dep-1);
}
int main() {
int x,l,r; ll ans,lastAns;
n=read(9),m=read(9);
rep(i,1,n) x=read(9),div(x),modify(rt[i],rt[i-1],x,30);
while(m--) {
l=read(9),r=read(9); lastAns=ans=0;
while(233) {
div(ans+1);
ans=query(rt[r],30)-query(rt[l-1],30);
if(lastAns==ans) {print(ans+1,'\n'); break;}
else lastAns=ans;
}
}
return 0;
}