标签:math 题目 ref 假设 最优 return main pre min
题目链接:https://atcoder.jp/contests/arc122/tasks/arc122_d
给定一个长度为 \(2n\) 的序列,Alice 和 Bob 执行以下操作 \(n\) 次:
\(n\) 轮后总价值为每一轮价值的最大值。Alice 想最大化总价值,Bob 想最小化总价值。在两人都选择最优策略的情况下,求最后总价值是多少。
\(n\leq 2\times 10^5;0\leq a_i<2^{30}\)。
我们首先考虑二进制下最高位。假设这 \(2n\) 个数字二进制下最高位为 \(0\) 的有偶数个(显然为 \(1\) 的也有偶数个),那么 Bob 肯定是让 \(0\) 与 \(0\) 匹配,\(1\) 与 \(1\) 匹配。分成两部分继续考虑次高位,此时原问题变为了两个子问题。
如果这 \(2n\) 个数字二进制下最高位为 \(0\) 的有奇数个,那么显然在这一位无论怎么匹配最大值都是 \(1\)。直接找出异或和最小的两个让他们匹配显然是 Bob 的最优策略。用 Trie 实现即可。
所以其实这道题 Alice 只不过是一个工具人罢了。
时间复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
using namespace std;
const int N=400010,LG=29,Inf=2147483647;
int n,a[N];
struct Trie
{
int tot,ch[N*LG][2];
void clear()
{
for (int i=0;i<=tot;i++)
ch[i][0]=ch[i][1]=0;
tot=1;
}
void ins(int v)
{
int p=1;
for (int i=LG;i>=0;i--)
{
int id=(v>>i)&1;
if (!ch[p][id]) ch[p][id]=++tot;
p=ch[p][id];
}
}
int query(int v)
{
int ans=0,p=1;
for (int i=LG;i>=0;i--)
{
int id=(v>>i)&1;
if (ch[p][id]) p=ch[p][id];
else ans+=(1<<i),p=ch[p][id^1];
}
return ans;
}
}trie;
int solve(int l,int r,int dep)
{
if (dep<0 || l>r) return 0;
int k=l-1,ans=Inf;
while (k<r && !(a[k+1]&(1<<dep))) k++;
if ((k-l)&1) return max(solve(l,k,dep-1),solve(k+1,r,dep-1));
trie.clear();
for (int i=l;i<=k;i++) trie.ins(a[i]);
for (int i=k+1;i<=r;i++) ans=min(ans,trie.query(a[i]));
return ans;
}
int main()
{
scanf("%d",&n); n<<=1;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
cout<<solve(1,n,LG);
return 0;
}
标签:math 题目 ref 假设 最优 return main pre min
原文地址:https://www.cnblogs.com/stoorz/p/14879394.html