博主的 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;
}
posted on 2020-10-18 10:37  Oxide  阅读(242)  评论(0编辑  收藏  举报