昨晚没睡好,早上状态让人难绷。
容易想到将 a a a 从大到小排序,依次找到合法的 a i ′ a'_i ai′,记修改 a i → a i ′ a_i\rarr a'_i ai→ai′ 为次数为 p i p_i pi,将 p i , b i p_i,b_i pi,bi 逆序相乘即为答案。
考虑如何求解 a i ′ a'_i ai′,这是一个类似求 mex 的问题。
S o l u t i o n 1 Solution\ 1 Solution 1
联想到 [CSP-S 2023] 消消乐。可以看下题解的图,很像本题求 mex 的过程,想到可以用并查集求解。
不过我晕乎乎的没敢写。
int find(int x){
if(f[x]==0)return f[x]=x+1;
return f[x]=find(f[x]);
}
扫一遍 a i a_i ai 即可,由于 R ( f ) ∈ [ 1 , 1 0 9 ] \R(f)\in [1,10^9] R(f)∈[1,109],用 unordered_map 复杂度大概 O ( N log 2 N ) O(N\log^2N) O(Nlog2N)。
S o l u t i o n 2 Solution\ 2 Solution 2
根据贪心策略,当 a i < a j a_i<a_j ai<aj 时,若 a i a_i ai 至少要增大到 a j a_j aj ,此时 a i a_i ai 跨越 a j a_j aj 更优。
这个性质表现为包含性,类似括号序列。假如我们从左向右扫,满足后进先出,因此可以用栈模拟过程。
具体地,值域上每个位置
x
x
x 可以放一个
a
i
a_i
ai,因此扫一遍值域,加入
a
i
a_i
ai 的同时要求每个
x
x
x 上最多只能弹出一个
a
i
a_i
ai。值域
1
0
9
10^9
109,由于
n
≤
1
0
5
n\le 10^5
n≤105,意味着
a
i
a_i
ai 最多需要
1
0
5
10^5
105 个位置,因此可以当栈空时手动跳到下一个
a
i
a_i
ai 所在位置,复杂度
O
(
n
)
O(n)
O(n)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define dec(i,a,b) for(register int i=a;i>=b;i--)
using namespace std;
typedef unsigned long long ull;
const int N=1e6+5;
int n,a[N],b[N],p0,p[N];
ull ans;
inline int Rd(){
int s=0,w=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while (ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
int main(){
n=Rd();
rep(i,1,n) a[i]=Rd();rep(i,1,n) b[i]=Rd();
sort(a+1,a+n+1);sort(b+1,b+n+1,greater<int>());
stack<int> st;
int nw=1,x=1;
auto Push=[&](){while (nw<=n&&a[nw]==x) st.push(a[nw++]);};
while (1){
if(st.empty()){
if(nw<=n) x=a[nw],Push();
else break;
}
else Push();
p[++p0]=(x++)-st.top();st.pop();
}
sort(p+1,p+n+1);
rep(i,1,n) ans+=1llu*b[i]*p[i];
printf("%llu",ans);
}

188

被折叠的 条评论
为什么被折叠?



