zoukankan      html  css  js  c++  java
  • 「ROI 2018 Day 2」无进位加法

    「ROI 2018 Day 2」无进位加法

    题目大意:

    给出二进制数(a_1,ldots a_n),对于(b_1ldots b_n)

    满足(a_ileq b_i)(igoplus b_i=sum b_i),其中$igoplus $为异或和

    (sum b_i)最小值

    设长度量级为(N=sum len(a_i))

    (O(N^2-N^3)) , 从高到低确定答案的每一个位

    枚举当前位为0,下面的位为1,贪心确定是否存在方案

    检查一个答案是否合法:

    动态维护一个倒序的(a_i)集合,从高到低考虑每一个位置

    1.如果当前位为0:

    如果(a_i)中存在大于等于这一位的数,非法

    2.如果当前位为1:

    2-1.如果(a_i)中存在2个当前位为1的数,非法

    2-2.如果(a_i)中存在恰好一个,则将这个1用于这个(a_i),并将(a_i)去掉最高位后放回集合

    2-3.不存在,用这个(1)删除最大的一个(a_i)

    实际看来,这个贪心本身效率并不高

    [ ]

    优化1:快速确定答案最高位的可能范围

    (B=max{ len(a_i)+i-1})

    (len(Ans)in[B,B+1])

    上下界均可以由上面的贪心模拟得到

    [ ]

    优化2:快速维护(a_i)倒序

    显然在不断更改的过程中,当前的(a_i)一定是原先的某一个(a_i)的一段后缀

    考虑将所有这样的后缀排序,为了方便,用每一个最高的1来表示一个合法的后缀

    显然可以先按照后缀长度分类,同长度的后缀,按照后缀中下一个1出现的位置排序

    也就是一个类似基数排序个过程,额外维护每一个后缀中下一个出现的(1)所对应的后缀即可

    预处理复杂度为(O(Nlog N))

    同时,也可以用线段树快速维护插入/删除的排名,得到(B)的值,单次操作复杂度(O(log N))

    [ ]

    优化3

    称满足(len(a_i)+i-1=B)(i)( ext{critical number})

    (p)为最小的( ext{critical number}),也就是在贪心过程中第一个出现情况2-1./2-2.的位置

    决策答案为(B)还是为(B+1),也就是决策

    是用(len(a_p))这个位置删除(a_p)的最高位,还是用(len(a_p)+1)的位置删除(a_p)

    (([1,p-1])的部分一定会被删掉)

    ( ext{intended solution})采用暴力递归来完成确定每一位的这个操作

    Function Solve(Limit) Limit为当前可以使用的最高位的1
    	求得 B,p
    	删除 a[1,p-1]
    	删除 a[p]最高位
    	if B<=Limit and Solve(p-1) then
    		ans[len(a[p]),B]=1
    		return True
    	删除a[p]
    	if B+1<=Limit and Solve(p) then 
    		ans[len(a[p])+1,B+1]=1
    		return True
    	else return False
    end
    

    至于复杂度,官方题解给出为(O(N))次递归和删除/加入操作,最终复杂度为(O(Nlog N))

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,const T &b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,const T &b){ ((a<b)&&(a=b)); }
    char IO;
    int rd(){
    	int s=0;
    	while(!isdigit(IO=getchar()));
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return s;
    }
    
    typedef vector <int> V;
    const int N=3e5+10,INF=1e9+10;
    
    int n,m,I[N],L;
    char s[N];
    int fir[N],nxt[N],rk[N],len[N],id[N];
    V A[N];
    
    struct Affirmation_Of_My_Existence{
    	int s[N<<2],t[N<<2];
    	void Down(int p){
    		rep(v,p<<1,p<<1|1) t[v]+=t[p],s[v]+=t[p];
    		t[p]=0;
    	}
    	void Upd(int p,int l,int r,int ql,int qr,int x) {
    		if(ql>qr) return;
    		if(ql<=l && r<=qr) {
    			s[p]+=x,t[p]+=x;
    			return;
    		}
    		Down(p);
    		int mid=(l+r)>>1;
    		if(ql<=mid) Upd(p<<1,l,mid,ql,qr,x);
    		if(qr>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
    		s[p]=max(s[p<<1],s[p<<1|1]);
    	}
    	void Build(int p,int l,int r){ 
    		s[p]=len[id[l]]-INF;
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		Build(p<<1,l,mid),Build(p<<1|1,mid+1,r);
    	}
    	void Add(int x,int k){
    		x=rk[x];
    		Upd(1,1,m,x,x,INF*k),Upd(1,1,m,x+1,m,k);
    	}
    	// Find the first critical position "p", and return all the bits in [1,p]
    	void Get(int p,int l,int r,int x,V &R){
    		if(s[p]<0) return;
    		if(l==r) return R.pb(id[l]);
    		Down(p);
    		int mid=(l+r)>>1;
    		Get(p<<1,l,mid,x,R);
    		if(s[p<<1]!=x) Get(p<<1|1,mid+1,r,x,R);
    	}
    } T;
    
    int Solve(int L){
    	// L denotes the maxmium bit we can use
    	int B=T.s[1];
    	if(B<0) return 1;
    	if(B>L) return 0;
    	V R; T.Get(1,1,m,B,R);
    	int p=*R.rbegin(),l=len[p];
    	for(int i:R) T.Add(i,-1);
    	
    	// Try ans B , so we use bit [nxt,B] to delete the number [1,p-1] 
        // and the number a[p] will be set to a[p]-2^l
    	if(nxt[p]) T.Add(nxt[p],1);
    	if(Solve(l-1)) {
    		rep(i,l,B) s[i]=1;
    		return B+1;
    	}
    
    	// Try ans B+1 , so we use bit [nxt+1,B+1] to delete the [1,p]
    	if(nxt[p]) T.Add(nxt[p],-1);
    	if(B<L && Solve(l)) {
    		rep(i,l+1,B+1) s[i]=1;
    		return B+2;
    	}
    	for(int i:R) T.Add(i,1);
    	return 0;
    }
    
    int main(){
    	rep(i,1,n=rd()) {
    		scanf("%s",s); int l=strlen(s);
    		cmax(L,l);
    		drep(j,l-1,0) if(s[j]=='1') {
    			nxt[++m]=fir[i];
    			A[len[m]=l-j-1].pb(m);
    			fir[i]=m;
    		}
    	}
    	rk[0]=1e9;
    	int k=m;
    	rep(i,0,L-1) {
    		k-=A[i].size();
    		sort(A[i].begin(),A[i].end(),[&](int x,int y){ return rk[nxt[x]]<rk[nxt[y]]; });
    		for(int j:A[i]) id[rk[j]=++k]=j;
    		k-=A[i].size();
    	}
    	T.Build(1,1,m);
    	rep(i,1,n) T.Add(fir[i],1);
    	memset(s,0,sizeof s);
    	drep(i,Solve(INF)-1,0) putchar(s[i]^48);
    }
    
    
  • 相关阅读:
    抽样调查
    一次项目上线发布的感想
    Nginx failing to load CSS and JS files (MIME type error)
    securecrt-active
    golang-http-post
    remove-weknow-ac from mac chrome
    批量写入redis
    golang 修改数组中结构体对象的值的坑
    golang使用json生成结构体
    json定义
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14406094.html
Copyright © 2011-2022 走看看