• [20220208联考] 差量


    前言

    又被卷飞了。/jk

    题目

    这是一道交互题。

    有一个长度为 \(n\) 的数组 \(a\),里面的数字互不相同且都为不超过 \(10^9\) 的正整数,下标从 \(0\) 开始。有以下三种交互操作:

    1. 询问一个位置的值。
    2. 询问一个下标集合中元素两两的差的绝对值,返回顺序任意。如询问长度为 \(4\),则返回长度为 \(\frac{4\times (4-1)}{2}=6\)
    3. 回答。

    三个操作对应的函数为:

    int qry1(int pos)
    vector<int> qry2(const vector<int> &S)
    void answer(const vector<int> &ret)
    

    需要 #include "difference.h" 头文件。

    讲解

    嘛,交互题就那点套路,二分、倍增、分治,这道题用二分和分治。具体怎么想出来的,只能说人类智慧。

    题解看不懂(我觉得它有问题),但是卷爷一下就给我讲懂了!卷爷太强了!

    为方便讲解,下文的差可能指差的绝对值。

    首先我们问出 \(0\) 号位的值,并把全集问一次,可以得到极差。然后二分前缀,找到一个极值,问一下极值的值并与 \(0\) 号位比较即可知道这是最大值还是最小值,令极值位置为 \(jc\)。(我代码用的这个名字,尽管这个名字很蠢)

    这里用到了 \(2\)\(1\) 询问和 \(\log_2n\)\(2\) 询问。

    令除了 \(0\) 号位和找出来的那个极值的位置组成的集合为 \(S\),我们询问 \(S\)\(S\cup\{jc\}\),用后者减去前者即可得到 \(S\) 中所有位置与极值的差,现在的问题就是如何分配这些值。

    注意到所有的 \(a_i\) 互不相同,那么这些差的值也一定互不相同,把未成功分配的位置组成很多连续区间,每次将所有这些区间的前半段取出,一轮下来两次询问即可求出它们与极值的差。

    显然,一轮操作后每个区间的长度都会减半,所以这里会用到 \(2\log_2n\)\(2\) 询问。

    总共使用 \(1\) 询问 \(2\) 次,\(2\) 询问 \(3\log_2n\) 次,可以通过。

    由于n很小,所以不管写得多花里胡哨应该都不会TLE。

    代码

    代码实现难度很低
    //12252024832524
    #include "difference.h"
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 255;
    
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    //int qry1(int pos)
    //vector<int> qry2(const vector<int> &S)
    //void answer(const vector<int> &ret)
    vector<int> Query(int l,int r,int ex = 500)
    {
    	vector<int> Q;
    	for(int i = l;i <= r;++ i) if(i^ex) Q.emplace_back(i);
    	return qry2(Q);
    }
    vector<int> operator - (vector<int> A,vector<int> B)
    {
    	sort(A.begin(),A.end()); sort(B.begin(),B.end());
    	vector<int> ret; int now = 0,lena = A.size();
    	for(int i = 0,len = B.size();i < len;++ i)
    	{
    		while(A[now]^B[i]) ret.emplace_back(A[now++]);
    		++now; 
    	} 
    	while(now < lena) ret.emplace_back(A[now++]);
    	return ret;
    }
    vector<int> operator & (vector<int> A,vector<int> B)
    {
    	vector<int> ret;
    	sort(A.begin(),A.end()); sort(B.begin(),B.end());
    	int now = 0,lenb = B.size();
    	if(!lenb) return ret;
    	for(int i = 0,len = A.size();i < len;++ i)
    	{
    		while(now < lenb-1 && B[now] < A[i]) ++now;
    		if(A[i] == B[now]) ret.emplace_back(A[i]);
    	}
    	return ret;
    }
    struct node
    {
    	int l,r;
    	vector<int> val;
    };
    int ans[MAXN];
    void find(int n, int M1, int M2)
    {
    	vector<int> ret,Q; ans[0] = qry1(0);
    	int m = 0; ret = Query(0,n-1);
    	for(int i = 0,len = ret.size();i < len;++ i) m = Max(m,ret[i]);
    	int l = 1,r = n-1,jc = 1;
    	while(l <= r)
    	{
    		int mid = (l+r) >> 1,win = 0;
    		ret = Query(0,mid);
    		for(int i = 0,len = ret.size();i < len && !win;++ i) if(ret[i] == m) win = 1;
    		if(win) jc = mid,r = mid-1;
    		else l = mid+1;
    	}
    	ans[jc] = qry1(jc);
    	ret = Query(1,n-1) - Query(1,n-1,jc);
    	vector<node> q[2];
    	if(1 < jc) 
    	{
    		if(jc < n-1) q[0].emplace_back(node{1,jc-1,ret-(Query(jc,n-1)-Query(jc+1,n-1))});
    		else q[0].emplace_back(node{1,jc-1,ret});
    	}
    	if(jc < n-1)
    	{
    		if(1 < jc) q[0].emplace_back(node{jc+1,n-1,ret-(Query(1,jc)-Query(1,jc-1))});
    		else q[0].emplace_back(node{jc+1,n-1,ret});
    	}
    	bool now = 0,to = 1;
    	while(!q[now].empty())
    	{
    		Q.clear(); bool wow = 0;
    		for(int i = 0,len = q[now].size();i < len;++ i)
    		{
    			if(q[now][i].l == q[now][i].r) ans[q[now][i].l] = q[now][i].val[0];
    			else
    			{
    				int mid = (q[now][i].l + q[now][i].r) >> 1;
    				for(int j = q[now][i].l;j <= mid;++ j) Q.emplace_back(j);
    				wow = 1;
    			}
    		}
    		if(!wow) break;
    		ret = qry2(Q); Q.emplace_back(jc); ret = qry2(Q) - ret;
    		for(int i = 0,len = q[now].size();i < len;++ i)
    			if(q[now][i].l ^ q[now][i].r) 
    			{
    				int mid = (q[now][i].l + q[now][i].r) >> 1;
    				q[to].emplace_back(node{q[now][i].l,mid,q[now][i].val & ret});
    				q[to].emplace_back(node{mid+1,q[now][i].r,q[now][i].val - (q[to].back().val)});
    			}
    		q[now].clear();
    		to = now; now ^= 1;
    	}
    	for(int i = 1;i < n;++ i)
    		if(i^jc)
    		{
    			if(ans[0] < ans[jc]) ans[i] = ans[jc] - ans[i];
    			else ans[i] = ans[jc] + ans[i];
    		}
    	ret.clear();
    	for(int i = 0;i < n;++ i) ret.emplace_back(ans[i]);
    	answer(ret);
    }
    
  • 相关阅读:
    星空Password
    股票交易
    【1】博客目录
    事务
    C#基础索引
    C# String
    MSIL
    Evaluation Stack
    Spring源码编译以及导入Intellij IDEA的操作步骤
    WebFlux响应式编程简单示例
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15871998.html
Copyright © 2020-2023  润新知