ABC277D 题解
__vector__ · · 题解
题外话
不知道为啥别人都用的并查集。
我赛时写的记忆化搜索过去的。
做法
把题目画出来,就是所有
然后现在我们要让剩下的值最少,转化一下就是让选择的数字总值最大,其实就是找一条路径,使得路径权值和最大。
我们进行建边,首先所有相同数字都可以互相到达,到达了一个数,就可以走到其他所有相同的数。
所以基于尽可能多选的贪心,我们可以把相同的数缩成一个点。
缩完点之后,将每个数组中出现过的数
然后依次枚举从
爆搜的时候把答案记一下就行了,就是记忆化。
复杂度
那个 log 是 map 的。
用 unordered_map 可以
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m;
ll a[maxn];
map<ll,ll> cnt;
map<ll,bool> vis;
map<ll,ll> ans;
void dfs(ll num)
{
if(cnt.find(num)==cnt.end())
{
return;
}
if(vis.find(num)!=vis.end())
{
return;
}
vis[num]=1;
dfs((num+1)%m);
ans[num]=ans[(num+1)%m]+cnt[num];
// printf("ans[%d]: %d\n",num,ans[num]);
}
int main()
{
ll sum=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
cnt[a[i]]++;
}
sort(a+1,a+n+1);
n=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++)
{
cnt[a[i]]=cnt[a[i]]*a[i];
}
for(int i=1;i<=n;i++)
{
if(vis.find(a[i])==vis.end())
{
dfs(a[i]);
}
}
ll out=0;
for(int i=1;i<=n;i++)
{
out=max(out,ans[a[i]]);
}
printf("%lld",sum-out);
return 0;
}