1617E - Christmas Chocolates
题目描述:
给出一个长度为 n n n 的序列 a a a,现在可以选择一对下标 ( x , y ) (x,y) (x,y),并进行如下操作,直到满足 a x = a y a_x=a_y ax=ay。
每次操作可以选择一个满足 a x ≤ 2 k a_x \leq 2^k ax≤2k 的非负整数 k k k,并且使 a x a_x ax 变为 2 k − a x 2^k-a_x 2k−ax
现在要求选择的一对下标满足其最优解(操作次数最少)在所有下标对中最大,输出这个下标对与操作次数
1 ≤ n ≤ 1 0 5 , 0 ≤ a i ≤ 1 0 9 1 \leq n \leq 10^5,0 \leq a_i \leq 10^9 1≤n≤105,0≤ai≤109
solution:
从图论的角度来思考问题,把每个整数作为一个点,当且仅当 i + j = 2 k i+j=2^k i+j=2k 次时, i i i 和 j j j 之间会产生一条无向边。那么整张图是一棵树的结构,论证如下:
- 结论: 对于任意
i
∈
[
0
,
1
0
9
]
i \in [0,10^9]
i∈[0,109],则有唯一的
j
∈
[
0
,
i
)
j \in [0,i)
j∈[0,i),使得
i
+
j
=
2
k
i+j = 2^k
i+j=2k 对于某个
k
k
k 成立
证明: 设 0 ≤ j 2 ≤ j 1 < i , i + j 1 = 2 k 1 , i + j 2 = 2 k 2 0 \leq j_2 \leq j_1 < i,i+j_1=2^{k_1},i+j_2=2^{k_2} 0≤j2≤j1<i,i+j1=2k1,i+j2=2k2,则 j 1 − j 2 = 2 k 1 − 2 k 2 = 2 k 2 ( 2 k 1 − k 2 − 1 ) j_1-j_2=2^{k_1}-2^{k_2}=2^{k_2}(2^{k_1-k_2}-1) j1−j2=2k1−2k2=2k2(2k1−k2−1),所以 j 1 ≡ j 2 ( m o d k 2 ) j_1 \equiv j_2 (\mod k_2) j1≡j2(modk2)。因为 i ≤ 2 k 2 i \leq 2^{k_2} i≤2k2,所有有 j 1 = j 2 j_1=j_2 j1=j2
这是一棵以 0 0 0 为根节点,以 a i a_i ai 为叶节点的树,那么现在就转换为一个树上直径问题,虽然数据规模有 1 0 9 10^9 109,但是实际上树的高度是 l o g log log 级别的,我们用树形DP直接求直径,总的复杂度就是 O ( n l o g n ) O(nlogn) O(nlogn)
但是这题中上述的树是为了方便抽象出来的,实际上是一棵由相关点集构成的虚树。因为当所有点都在以 0 0 0 为根的某一棵子树时,我们再以 0 0 0 为根去统计显然会贡献多余,因此我们需要处理。我们以叶子为根预先做一次 dfs,当某个节点既不出现在序列中,其子树中又没有相关点集,我们就不能用这个点更新值。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+10;
int n,x;
unordered_map<int,int> mp;
int o=0;
inline int find(int x){
for(int i=0;i<=30;i++){
if((1<<i)>=x) return 1<<i;
}
}
int head[maxn],to[maxn<<1],nex[maxn<<1],tot=0;
int f[maxn],idx[maxn],back[maxn],ansu,ansv,ans;
bool avi[maxn],vis[maxn];
inline void add(int u,int v){
to[++tot]=v;
nex[tot]=head[u];
head[u]=tot;
to[++tot]=u;
nex[tot]=head[v];
head[v]=tot;
}
void pre_dfs(int u,int fa){
for(int i=head[u];i;i=nex[i]){
int v=to[i];
if(v==fa) continue;
pre_dfs(v,u);
vis[u]|=vis[v];
}
//cout<<u<<":"<<vis[u]<<endl;
}
void dfs(int u,int fa){
f[u]=0;
idx[u]=u;
for(int i=head[u];i;i=nex[i]){
int v=to[i];
if(v==fa) continue;
dfs(v,u);
if(f[v]+1+f[u]>ans&&vis[v]) ans=f[u]+f[v]+1,ansu=idx[u],ansv=idx[v];
if(f[v]+1>f[u]&&vis[v]) f[u]=f[v]+1,idx[u]=idx[v];
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
if(!mp.count(x)) mp[x]=++o;
else{
back[mp[x]]=i;
vis[mp[x]]=1;
continue;
}
back[mp[x]]=i;
vis[mp[x]]=1;
while(x){
int y=find(x)-x;
if(!mp.count(x)) mp[x]=++o;
if(!mp.count(y)) mp[y]=++o;
else{
add(mp[x],mp[y]);break;
}
add(mp[x],mp[y]);
x=y;
}
}
pre_dfs(1,0);
dfs(1,0);
cout<<back[ansu]<<" "<<back[ansv]<<" "<<ans<<endl;
return 0;
}