zoukankan      html  css  js  c++  java
  • loj#2985. 「WC2019」I 君的商店

    题目描述

    https://loj.ac/problem/2985

    太长了不写

    题解

    刚了几天刚出了69分加一些奇奇怪怪的做法

    subtask3

    首先根据0和N-1可以找到1连续段的开头,然后二分

    把不确定性消掉,只需要两个一组询问即可,根据奇偶性讨论之后的和只有0和2

    subtask5

    首先用2N的次数找到最大值,最大值一定是1

    然后对于任意两个数xy,先用2次来保证x>=y,然后3次询问x+y与1的大小关系

    如果x+y>=1则x=1,否则y=0,最后剩下的一个数根据奇偶性求出来

    总次数是7N

    瞎搞

    没有写并不知道结果怎样

    在求最大值的时候启发式合并,合出来的东西是一棵深度log有N/2个叶子的树

    从上往下按照树边询问,因为大小关系已经确定所以只需要3次

    如果当前节点已经可以确定为1就往子树里搞,因为再搞下去可能得不到新的信息(如果某个点确定为0那么子树都是0),最后剩下的再用subtask5的做法5*个数来搞

    最坏情况下剩下的都是叶子,也就是说每个非叶子节点都询问了一次,那么次数是2N+3*N/2+5*N/2=6N

    从叶子开始考虑可以更优,因为一旦一个点是1那么到根的路径都是1

    次数不知道是多少但是感觉查找的部分可以变成3*N/4,也就是总次数是21/4*N

    subtask6

    subtask5的瓶颈在于用2N次来确定1,因为M=5N+100,所以考虑不确定具体的1而是得到一个单调的序列,最后用二分解决

    维护一个数a和剩余数序列,每次提出两个数xy来考虑

    首先用2次保证x>=y,然后询问x+y与a的关系

    如果a>=x+y那么y=0把x丢回去,否则有x>=a,把a变成x把y丢回去

    把所有的a按顺序记下来,得到一个单调不减的序列和剩下的一个不确定数,用二分把数插进序列

    由于max(ai,z)=1,所以得到1之后同subtask3二分确定序列

    次数是5N+5log,如果不把数插进去直接二分可以做到3log但是不好写所以没写

    code

    #include <bits/stdc++.h>
    #include "shop.h"
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define ll long long
    using namespace std;
    
    void swap(int &x,int &y) {int z=x;x=y;y=z;}
    void find_price(int task_id, int N, int K, int ans[]) {
    	int a[100001],b[100001],c[100001],d[100001],i,j,k,l,r,mid,t1=0,t2=0,x,y,z,sum,A,t;
    	bool bz;
    	
    	if (task_id==3)
    	{
    		fo(i,1,N) a[i-1]=i-1,b[N-i]=i-1;
    		a[0]=0;b[0]=N-1;
    		bz=query(a,1,b,1);
    		
    		l=1;r=(N-!K)/2-1;
    		while (l<r)
    		{
    			mid=(l+r)/2;
    			a[0]=0,b[0]=mid*2-1+(!K),b[1]=mid*2+(!K);
    			if (bz)
    			a[0]=(N-1)-a[0],b[0]=(N-1)-b[0],b[1]=(N-1)-b[1];
    			
    			if (query(a,1,b,2))
    			l=mid+1; else r=mid;
    		}
    		a[0]=0,b[0]=l*2-1+(!K),b[1]=l*2+(!K);
    		if (bz)
    		a[0]=(N-1)-a[0],b[0]=(N-1)-b[0],b[1]=(N-1)-b[1];
    		l-=!query(a,1,b,2);
    		
    		ans[0]=1;if (!K) ans[1]=1;
    		fo(i,1,l) ans[i*2-1+(!K)]=ans[i*2+(!K)]=1;
    		if (bz)
    		{
    			fo(i,1,N/2)
    			swap(ans[i-1],ans[(N-i+1)-1]);
    		}
    	}
    	else
    	{
    		l=N-1;
    		fo(i,1,N-1) c[i]=i;A=0;t=1;d[t]=0;
    		while (l>1)
    		{
    			x=c[l-1],y=c[l],l-=2;
    			a[0]=x,b[0]=y;
    			if (query(a,1,b,1)) swap(x,y);
    			
    			a[0]=A,b[0]=x,b[1]=y;
    			if (!query(a,1,b,2))
    			ans[y]=0,c[++l]=x;
    			else
    			A=x,c[++l]=y,d[++t]=x;
    		}
    		
    		a[0]=c[1],b[0]=d[t];
    		if (!query(a,1,b,1)) l=t+1;
    		else
    		{
    			l=1;r=t;
    			while (l<r)
    			{
    				mid=(l+r)/2;
    				a[0]=c[1],b[0]=d[mid];
    				if (!query(a,1,b,1))
    				l=mid+1; else r=mid;
    			}
    		}
    		fd(i,t+1,l+1) d[i]=d[i-1];d[l]=c[1];++t;
    		
    		fd(i,t/2,1) swap(d[i],d[t-i+1]);
    		l=1;r=(t-1-!(K&1))/2;
    		while (l<r)
    		{
    			mid=(l+r)/2;
    			a[0]=d[1],b[0]=d[mid*2+!(K&1)],b[1]=d[mid*2+1+!(K&1)];
    			if (query(a,1,b,2))
    			l=mid+1; else r=mid;
    		}
    		if (l>r) --l;
    		else
    		{
    			a[0]=d[1],b[0]=d[l*2+!(K&1)],b[1]=d[l*2+1+!(K&1)];
    			l-=!query(a,1,b,2);
    		}
    		
    		fo(i,1,l*2+1+!(K&1)) ans[d[i]]=1;
    	}
    }
    
  • 相关阅读:
    [读书笔记]-技术学习-微服务架构与实践
    [文章转载]-Java后端,应该日常翻看的中文技术网站 -江南白衣
    [文章转载]-我的Java后端书架-江南白衣
    正则表达式有多强大一看便知!
    微信小程序支付功能完整流程
    判断字符串是否合法(1)
    ES6新增常用方法
    JS求一个字符串在另一个字符串中出现的次数
    根据对象的某个属性排序
    数组去除重复值的四种超简便方法
  • 原文地址:https://www.cnblogs.com/gmh77/p/13476309.html
Copyright © 2011-2022 走看看