[ICPC2022 Jinan R] Tower
和 lyt 组队随便打了打。
翻译:给定
-
将
a_{i} 加上1 。 -
将
a_{i} 减去1 。 -
将
a_{i} 除以2 。
每次操作代价为
- 数据范围:多测
1 \le T \le 10 ,1 \le m < n \le 500 ,1 \le a_{i} \le 10^9 。
首先发现
但按照题目的意思枚举删哪些点肯定行不通。于是我们考虑枚举最终变成的那个值,然后计算所有点变成那个值的代价,删掉最大的
但是值域有
容易猜答案存在于某个数不断除以
于是我们惊人的发现 AC 了。复杂度是
- 现在我们考虑证明。
我们只需证明答案不在除以
显然,在这个问题中,若
为什么不会是中间点加减
因此原问题类比这个问题可得答案一定在除以
code:
#include<bits/stdc++.h>
using namespace std;
#define N 505
#define int long long
int n,m,i,j,ans,a[N],t,s[N];
vector<int>G;
signed main(){
scanf("%lld",&t);
while(t--){
G.clear();
scanf("%lld%lld",&n,&m),ans=1e9;
for(i=1;i<=n;i++) scanf("%lld",&a[i]);
for(i=1;i<=n;i++){
int k=a[i];
while(k){
G.push_back(k);
k>>=1;
}
}
for(int y:G){
for(i=1;i<=n;i++) s[i]=1e9;
for(i=1;i<=n;i++){
int k=a[i],cnt=0;
while(k>=1){
s[i]=min(s[i],cnt+abs(k-y));
k>>=1,cnt++;
}
}
sort(s+1,s+1+n);
int sum=0;
for(i=1;i<=n-m;i++) sum+=s[i];
ans=min(ans,sum);
}
printf("%lld\n",ans);
}
return 0;
}