问题链接(https://codeforces.com/problemset/problem/1165/E)
问题分析
给出f(l,r)的公式为f(l,r)=∑l<=i<=r aibi,现在要可以改变bi的次序,但ai不变,求∑1<=l<=r<=n f(l,r)的最小值。
设要求的值为sum=∑1<=l<=r<=n ∑l<=i<=r aibi,对这个式子展开,把相同的项合并,可以发现每一项都可以写成(n-i+1)iai*bi的形式,因为有x1×y1+x2×y2>=x1×y2+x2×y1,这里x1<=x2,y1<=y2,也就是用x序列中最小的与y序列中最大的相乘和x序列中次大的与y序列中次小的相乘等求和的结果是最小的。有因为ai的位置不不变的,所以把(n-i+1)iai看成整体ci,然后对ci排序,对bi以相反的规则排序,再让它们相乘后求和式的,得到的结果一定是最小的。
注意:要用long long避免溢出,且对ci排序之前,不要取模,否则排序结果会出错。
程序如下
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
//a1b2+a2b1<=a1b1+a2b2
//one=(n-i+1)*i*ai*bi
typedef long long ll;
const int mod=998244353;
const int N=2e5+5;
ll a[N],b[N];
bool cmp(ll x,ll y){
return x>y;
}
int main(){
ll n,i,ans;//注意避免溢出
scanf("%lld",&n);
for(i=1;i<=n;i++){
scanf("%lld",a+i);
a[i]*=(n-i+1)*i;
}
for(i=1;i<=n;i++) scanf("%lld",b+i);
sort(a+1,a+n+1);//排序前不要对a取模
sort(b+1,b+n+1,cmp);
ans=0;
for(i=1;i<=n;i++){
ans+=(a[i]%mod)*b[i];
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}