专栏文章
题解:P14567 【MX-S12-T2】区间
P14567题解参与者 3已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @min325bs
- 此快照首次捕获于
- 2025/12/01 19:45 3 个月前
- 此快照最后确认于
- 2025/12/01 19:45 3 个月前
赛时想到的神秘做法。
我们先记下每种颜色第一次出现的位置,然后给每个其它位置赋一个随机大权值,这样赋完后再将每种颜色第一次出现的位置的权值赋为该颜色其余权值和的相反数。
显然这样可以保证同种颜色的所有权值之和为 。我们对权值序列做前缀和,那么任意两个前缀和相同的位置中间的区间一定是合法的。
由于题目保证 单调不减,选择一个完全包含了其它合法区间的大区间更新答案一定不优,同理,若有多个位置的前缀和相同,只需要在每两个相邻位置间更新一次答案。
使用
map 记录每种前缀和上次出现的位置即可做到 。代码
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N=1e6+5;
const int p=1e12;
int n,c[N],v[N],f[N];
int a[N],fi[N],sum[N],ssum[N];
mt19937 rnd(114514);
map<int,int>mp;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++)cin>>v[i];
for(int i=1;i<=n;i++)cin>>f[i];
for(int i=1;i<=n;i++)
if(fi[c[i]]==0)
fi[c[i]]=i;
for(int i=n;i>=1;i--)
{
if(i!=fi[c[i]])a[i]=rnd()%p,sum[c[i]]+=a[i];
else a[i]=-sum[c[i]];
}
for(int i=1;i<=n;i++)ssum[i]=ssum[i-1]+a[i];
mp[0]=0;
int lt=0,ans=1e18;
for(int i=1;i<=n;i++)
{
if(mp.count(ssum[i]))
{
int l=mp[ssum[i]]+1,r=i;
if(l>lt)
{
int now=0;
for(int j=l;j<=r;j++)
now+=v[j]*f[j-l+1];
ans=min(ans,now);
lt=l;
}
}
mp[ssum[i]]=i;
}
cout<<ans;
return 0;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...