传送门:
引用站外地址
【ABC254Ex】 Multiply or Divide by 2
洛谷
题意
给你两个集合 A 和 B ,你可以把集合 A 的任意一项变为原来的 $\left \lfloor\frac{1}{2}\right \rfloor $ 或 2 倍,求至少需要操作几步才能使 A=B。如果无法将 A 变为 B,输出 -1
。
解析
考虑贪心,可以将“把 A 的任意元素变为原来的两倍”转换为“把 B 的任意元素变为原来的 21”,这两个方法是等效的。
我们维护两个优先队列 a
和 b
代表集合 A 和 B ,每次取出两个集合的最大值进行转化,然后我们采用这样的贪心策略:
如果 a.top()==b.top()
,那么直接将这两个元素出队,这说明两个集合的这两个元素已经相等了。
如果 b.top()>a.top()
,那么将 b.top()
出队,除以2后再入队,这等价于将 集合 A 的最大值乘上2。
大家应该意识到了一个问题,如果将 b.top()
除以2的话,实际上是和 a.top()*2
的效果并不完全一样,因为除以2时会向下取整,所以到后面会一直多一个 1 而无法将 A 变为 B,这种情况就需要输出 -1
了。
接下来如果 a.top()>b.top()
的话,跟上面一样,将 a.top()
出队,除以2后再入队即可,不需要考虑其他条件,因为在题意中已经说到需要向下取整了。
代码
那么代码就很简单了,使用优先队列维护即可,单次修改(除 a.top()==b.top()
时)执行 cnt++
,最后输出 cnt
作为答案即可。
注释版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <bits/stdc++.h> using namespace std; int n,t,cnt; priority_queue<int> a,b; int main(){ ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) cin>>t,a.push(t); for(int i=1;i<=n;i++) cin>>t,b.push(t); while(!a.empty()){ if(a.top()==b.top()) a.pop(),b.pop(); else if(a.top()>b.top()){ t=a.top(); a.pop(),a.push(t>>1),cnt++; } else if(b.top()>a.top()){ if(b.top()&1) cout<<"-1",exit(0); t=b.top(); b.pop(),b.push(t>>1),cnt++; } } cout<<cnt; return 0; }
|
无注释版
可以CTJ的版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <bits/stdc++.h> using namespace std; int n,t,cnt; priority_queue<int> a,b; int main(){ ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) cin>>t,a.push(t); for(int i=1;i<=n;i++) cin>>t,b.push(t); while(!a.empty()){ if(a.top()==b.top()) a.pop(),b.pop(); else if(a.top()>b.top()){ t=a.top(); a.pop(),a.push(t>>1),cnt++; } else if(b.top()>a.top()){ if(b.top()&1) cout<<"-1",exit(0); t=b.top(); b.pop(),b.push(t>>1),cnt++; } } cout<<cnt; return 0; }
|
multiset做法
我这里提供一种 multiset
的做法,闲的没事写的(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <bits/stdc++.h> using namespace std; int n,t,cnt; multiset<int> a,b; int main(){ ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) cin>>t,a.emplace(t); for(int i=1;i<=n;i++) cin>>t,b.emplace(t); while(!a.empty()){ if(*a.rbegin()==*b.rbegin()) a.erase(--a.end()),b.erase(--b.end()); else if(*a.rbegin()>*b.rbegin()){ t=*a.rbegin(); a.erase(--a.end()),a.emplace(t>>1),cnt++; } else if(*a.rbegin()<*b.rbegin()){ if((*b.rbegin())&1) cout<<"-1",exit(0); t=*b.rbegin(); b.erase(--b.end()),b.emplace(t>>1),cnt++; } } cout<<cnt; return 0; }
|
【ABC254Ex】 Multiply or Divide by 2 题解