zoukankan      html  css  js  c++  java
  • 题解 [WC2019]I 君的商店

    题解 [WC2019]I 君的商店

    题目链接

    有被这道题目人类智慧到,想了好久还是和正解没有挨边,最后还是迫不得已看了题解。 /kk

    题目分析


    以下记录我想这道题目的思考过程。

    先看看可不可以找到一些特殊性质,可以发现可以通过 (mathcal O(2n)) 的时间复杂度找到一个一定是 1 的位置,并且在知道 1 的奇偶性的前提下可以比较两个集合的严格大小关系。

    然后观察所有子任务,可以看到子任务 3 特别奇怪,相当于是保证了所有 0 和所有 1 构成了两个连续段(暗示二分,并且由 (M=100) 也可以猜到复杂度大概是 (mathcal O(log_2n)) 级别的), 1 的位置比较好找,并且题目中一开始还给定了 1 的数量的奇偶性,如果要二分的话需要保证返回的是严格小于或者严格大于,所以可以根据 1 的数量的奇偶性来将相邻两个数字捆绑在一起,这样在询问的时候询问要么就是 1+1 与 1 或者 0+0 与 1 的大小关系,返回的就是严格小于或者严格大于,时间复杂度是 (mathcal O(3log_2n))

    子任务 5 和 6 额外给出了 100 的复杂度,说明正解大概是先将数组进行一些处理让数组满足子任务 3 的限制(相当于是要排序),于是问题的关键转到排序上。

    如何将数组排序?我一开始想到的是增量法,已经给 (0sim i-1) 的所有元素排好序了,接下来考虑把 (i) 这个元素加入,然后想了很多方法都没有想到简单的判断 (i) 这个元素可以插入哪里的方法。最后在这里放弃了。

    归并排序是后面想到的,不过这样的时间复杂度是 (mathcal O(2nlog_2n)) 的。


    这里是 (mathcal O(7n)) 的做法。

    先通过 (mathcal O(2n)) 找到 1 ,然后对于两个数 (x,y) ,可以先比较 (operatorname{ans}[x])(operatorname{ans}[y]) 的关系,通过交换操作使得 (operatorname{ans}[x]le operatorname{ans}[y]) ,然后比较 (operatorname{ans}[x]+operatorname{ans}[y]) 与 1 的关系,如果 (operatorname{ans}[x]+operatorname{ans}[y]le 1) 可以得出 (operatorname{ans}[x]=0) ,如果 (operatorname{ans}[x]+operatorname{ans}[y]ge 1) 可以得出 (operatorname{ans}[y]=1) ,所以可以通过 (mathcal O(5)) 的时间复杂度确定 (x,y) 中的一个元素,确定完 (n-2) 个元素后最后一个元素通过给定的 1 的奇偶性确定,总的时间复杂度是 (mathcal O(7n)) 的。


    接下来是正解做法。

    先考虑子任务 3 ,直接二分 (operatorname{mid}) 通过 (operatorname{ans[mid]+ans[mid+1]})和 1 的大小关系来判断位置在左边还是在右边,最后仅仅不能确定找到的位置的那个地方是 0 还是 1 ,这个可以通过 1 的奇偶性确定是 0 还是 1 。

    然后看子任务 6 ,可以猜出时间复杂度大概是 (mathcal O(5n)) 。先令 (x=0,z=1) ,然后从 (2)(N-1) 枚举 (y) ,先比较 (operatorname{ans}[x])(operatorname{ans}[y]) 的大小关系,然后通过交换 (x,y) 使得 (operatorname{ans}[x]le operatorname{ans}[y]) ,再比较 (operatorname{ans}[x]+operatorname{ans}[y])(operatorname{ans}[z]) 的关系,如果返回结果为 (operatorname{ans}[x]+operatorname{ans}[y]le operatorname{ans}[z]) 说明 (operatorname{ans}[x]=0) ,确定后在把 (y) 当作新的 (x) ,否则的话说明返回结果为 (operatorname{ans}[x]+operatorname{ans}[y]ge operatorname{ans}[z]) ,可以得出 (operatorname{ans}[y]ge operatorname{ans}[z]) ,将 (z) 放入一个数组 (H[]) 并且将 (y) 当作新的 (z) 。最后将 (z) 继续放入 (H[]) ,可以发现得到的 (H[]) 是单调递增的,此时无法确定的元素就只剩了 (H[])(x) ,用二分的方法可以确定 (H[]) 中的大部分元素,不妨设无法确定的元素为 (H[operatorname{pos}]) ,可以通过比较 (H[]) 中的最大值和 (x) 得到值为 1 的元素,然后通过 (mathcal O(5)) (见 (mathcal O(7n)) 的做法)的时间复杂度确定 (H[operatorname{pos}])(x) 中的一个元素,另一个用给定的 1 的奇偶性确定。总的时间复杂度就是 (mathcal O(5n+3log_2n)) 的。


    参考代码

    #include"shop.h"
    int S[5],T[5],nS,nT;
    int query0(int x,int y){
    	nS=1;S[0]=x;nT=1;T[0]=y;
    	return query(S,nS,T,nT);
    }
    int query1(int x,int y,int z){
    	nS=2;S[0]=x,S[1]=y;nT=1;T[0]=z;
    	return query(S,nS,T,nT);
    }
    const int maxn=100005;int spe[maxn];
    void find_price(int task_id,int N,int K,int ans[]){
    	if(N==1)return ans[0]=1,void();
    	int x=0,z=1,cnt=0,tp=-1,az=0;
    	if(task_id==3){
    		if(query0(0,N-1)){
    			tp=N-1;
    			for(int i=0;i<N;++i)
    				spe[cnt++]=i;
    		}
    		else{
    			tp=0;
    			for(int i=N-1;i>=0;--i)
    				spe[cnt++]=i;
    		}
    		x=-1;z=spe[0];
    	}
    	else{
    		for(int i=2;i<N;++i){
    			int y=i;
    			if(!query0(x,y))x^=y^=x^=y;
    			if(query1(x,y,z))ans[x]=0,x=y;
    			else spe[cnt++]=z,z=y;
    		}
    		if(query0(x,z))tp=z;
    		else tp=x,spe[cnt++]=z;
    		spe[cnt++]=tp;
    	}
    	ans[tp]=1;az^=1;
    	if(cnt==1)return ans[x]=K^az,void();
    	int l=0,r=cnt-2,mid=0;
    	while(l<r){
    		mid=(l+r)>>1;
    		if(query1(spe[mid],spe[mid+1],tp))l=mid+1;
    		else r=mid;
    	}
    	mid=l=r;
    	for(int i=0;i<mid;++i)ans[spe[i]]=0;
    	for(int i=mid+1;i<cnt-1;++i)ans[spe[i]]=1,az^=1;
    	if(tp==z){
    		if(!query0(x,spe[mid]))x^=spe[mid]^=x^=spe[mid];
    		if(query1(x,spe[mid],tp))ans[x]=0;
    		else ans[spe[mid]]=1,az^=1,spe[mid]=x;
    	}
    	ans[spe[mid]]=K^az;
    	return;
    }
    
  • 相关阅读:
    WPF 中使用 Resource 实现多语言
    webapi入门 如何调用
    webapi入门2
    webapi 入门
    asp.net web page 中如何添加引用
    几个Is函数
    webGrid内容格式化
    Validation
    HTML FORM
    访问数据库
  • 原文地址:https://www.cnblogs.com/lsq147/p/14527707.html
Copyright © 2011-2022 走看看