MX 暑假集训 7.12
【25時、ナイトコードで。×鏡音リン】限りなく灰色へ(向着无尽之灰)
太棒了学了好久的 dp 优化结果发现写出 \(n^2\) 式子只剩 \(20\) 分钟了,根本来不及优化。
[APIO2016] 最大差分
题意
有一个隐藏的长度为 \(n\) 的数组 \(a\) 满足 \(0\le a_1< a_2<a_3<\dots <a_n\le 10^{18}\),你每次可以给定 \([s,t]\) 并询问 \(a_i\in [s,t]\) 中 \(a_i\) 的最大与最小值,你需要找出 \(a_{i+1}-a_{i}(1\le i\le n-1)\) 的最大值,有以下两个子任务。
-
在 \(\left\lfloor \frac{n+1}{2} \right\rfloor\) 次询问内求出最大值;
-
令每次出现在 \([s,t]\) 中的 \(a_i\) 个数为 \(k\) 个,你总共询问了 \(m\) 次,则每次询问的 \(k\) 之和加上 \(m\) 不超过 \(3n\),即 \(\sum(k+1)\le 3n\)。
solution
子任务 \(1\) 是简单的,每次询问值域并记录最大最小值,再缩减值域至最大最小值之间即可。
子任务 \(2\) 这个限制有些严,肯定不是分治状物了,考虑一下分块。
对值域做分块尝试缩减成子问题是不可取的,因为根本缩减不过来,而且扫一遍值域的复杂度太高了。
考虑从答案入手,如果我们知道了 \(a_1\) 和 \(a_n\) 的值,那么答案不小于 \(\left\lceil \frac{a_n-a_1}{n-1}\right\rceil\),令这个值为 \(B\),对值域分块,那么块内不可能有答案,考虑跨块的答案即可。
找到 \(a_1,a_n\) 是 \(n+1\) 的代价,块内是 \(n-1\) 次询问,问到了 \(n-2\) 个数,所以总代价不超过 \(3n-2\),可以通过。
Code
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
extern "C" void MinMax(long long,long long,long long*,long long*);
extern "C" long long findGap(int,int);
long long findGap(int T,int n) {
if (T==1) {
vector<ll> v1,v2,tmp;
ll mn=-1,mx=1000000000000000000LL+1;
int Tim=(n+1)/2;
while (Tim--) {
MinMax(mn+1,mx-1,&mn,&mx);
v1.push_back(mn);
v2.push_back(mx);
}
reverse(v2.begin(),v2.end());
for (ll x:v1) tmp.push_back(x);
for (ll x:v2) tmp.push_back(x);
ll lst=-1,ret=0;
for (ll x:tmp) {
if (lst!=-1) ret=max(ret,x-lst);
lst=x;
}
return ret;
}
ll mx=0,mn=0;
MinMax(0,1000000000000000000LL,&mn,&mx);
ll ret=0,B=(mx-mn)/(n-1)+((mx-mn)%(n-1)!=0),lst=mn;
for (ll L=mn+1;L<mx;L+=B) {
ll nL=0,nR=0;
MinMax(L,min(L+B-1,mx-1),&nL,&nR);
if (nL!=-1) {
ret=max(ret,nL-lst);
lst=nR;
}
}
ret=max(ret,mx-lst);
return ret;
}
[JOISC 2016] 神经衰弱 / Memory2
题意
有 \(n\) 种卡牌,每种各两张,将卡牌全部摆在桌上形成长度为 \(2n\) 的序列 \(a\),初始时,你并不知道 \(a\) 中的数是什么。
你可以进行如下操作。
- 指定两个位置 \(i,j\),若 \(P_{a_i}>P_{a_j}\) 则返回 \(a_i\),否则返回 \(a_j\),其中 \(P\) 是一个内置的确定的权重排列。
你需要在 \(k\) 次操作内确定序列 \(a\)。
\(1\le n\le 50,k=300\)。
solution
不会做,只会 \(P_i=i\) 的特殊性质。
我们发现,确定一个位置 \(x\),将其与其他所有位置都比较一遍,记录所有返回值的次数,一定会有且仅有一个返回值出现奇数次,这个数就是 \(x\) 位置的值,原因是其他的数成对出现,贡献一定为 \(0\) 或 \(2\)。
每次随机选择 \(x\),将其与所有未确定位置询问一遍,若一个位置与其询问的结果不为位置 \(x\) 上的值,那么可以确定这个位置。
期望次数为 \(T(n)=n+T(\frac{n}{2})=2n\),精细实现可以轻松通过。
有 \(300\) 次和 \(250\) 次的确定性做法,但是不会喵。
Code
#include<cstdio>
#include<algorithm>
#include<vector>
#include<random>
#include "Memory2_lib.h"
using namespace std;
#define ll long long
#define qwq Ff472130
#define f(i,l,r) for (int i=l;i<=r;i++)
#define F(i,l,r) for (int i=l;i>=r;i--)
mt19937 Ff(8566);
inline int rnd(int l,int r) {
ll k=Ff();
return l+k%(r-l+1);
}
inline int ask(int x,int y,vector<vector<int>> &mp) {
if (mp[x][y]!=-1) return mp[x][y];
return mp[x][y]=mp[y][x]=Flip(x,y);
}
void Solve(int T,int n) {
if (n==1) return Answer(0,1,0);
vector<vector<int>> mp;
f(i,1,n*2) {
vector<int> init;
f(j,1,n*2) init.push_back(-1);
mp.push_back(init);
}
vector<int> id,t(n*2),col[60],vis(n*2);
f(i,0,n*2-1) id.push_back(i);
while (1) {
if (id.size()==2) {
col[ask(id[0],id[1],mp)].push_back(id[0]);
col[ask(id[0],id[1],mp)].push_back(id[1]);
break;
}
int k=id[rnd(0,id.size()-1)],val=-1;
if (vis[k]) continue;
if (id.size()>20) {
vector<int> chk;
int pos=rnd(0,id.size()-1);
while (pos==k) pos=rnd(0,id.size()-1);
chk.push_back(ask(k,pos,mp));
pos=rnd(0,id.size()-1);
while (pos==k) pos=rnd(0,id.size()-1);
chk.push_back(ask(k,pos,mp));
pos=rnd(0,id.size()-1);
while (pos==k) pos=rnd(0,id.size()-1);
chk.push_back(ask(k,pos,mp));
pos=rnd(0,id.size()-1);
while (pos==k) pos=rnd(0,id.size()-1);
chk.push_back(ask(k,pos,mp));
pos=rnd(0,id.size()-1);
while (pos==k) pos=rnd(0,id.size()-1);
chk.push_back(ask(k,pos,mp));
sort(chk.begin(),chk.end());
if (chk[0]==chk[1]&&chk[1]==chk[2]) continue;
if (chk[1]==chk[2]&&chk[2]==chk[3]) continue;
if (chk[2]==chk[3]&&chk[3]==chk[4]) continue;
}
vis[k]=1;
for (int x:id) if (x^k) t[ask(k,x,mp)]^=1;
f(i,0,n-1) if (t[i]) val=i,t[i]=0;
vector<int> nxt;
for (int x:id) {
if (x!=k&&ask(k,x,mp)!=val) col[ask(k,x,mp)].push_back(x);
else nxt.push_back(x);
}
id=nxt;
}
f(i,0,n-1) Answer(col[i][0],col[i][1],i);
}

浙公网安备 33010602011771号