求 S=i=1∑nj=1∑nmin(ai,bj) 的值。
求 S=i=1∑nj=1∑n∣ai−aj∣ 的值。
显然我们直接求比较难求,但是我们注意到这样的一个数学性质,即 min(x,y)=2x+y−∣x−y∣。我们就可以把这个最值求和问题转化为绝对值求和(形如 Intro. Prob. B)的问题。
同理,如果我们在这里求的是 S=i=1∑nj=1∑nmax(ai,bj),我们根据 max(x,y)=2x+y+∣x−y∣,也能转化为相似的形式。
一个办法是直接暴力 O(n2) 计算,但是对于比较大的 n 是肯定会超时的。
所以我们不妨利用数学性质:把数字 a 排序,然后 O(n) 计算 (i−1)×ai−∑j=1i−1aj 的总和即可。时间复杂度为 O(nlogn)(排序的时间复杂度),如果范围较小可以使用桶来优化到 O(n)。
题目
给定一个长度为 n 的 01 字符串串,定义 f(x) 为字符串 x 中某一字符的最大出现次数。求 l=1∑nr=l∑nf(slsl+1…sr)
我们先用记字符 c 在前缀 [1,i) 的出现次数为 prec,i,因此对于区间 [l,r],其在区间内的出现次数为 prec,r−prec,l。于是有某一字符的最大出现次数为 maxc ∈ {0,1}(prec,r−prec,l)=max(pre0,r−pre0,l,pre1,r−pre1,l)。
考虑到对于给定的 [l,r] 总是有 pre0,r−pre0,l+pre1,r−pre1,l=r−l+1,同时根据我们上面的推论,我们可以把上式转化为 2r−l+1+∣pre0,r−pre0,l−(pre1,r−pre1,l)∣,对于 2r−l+1,显然易求。所以我们考虑后面的部分,变形有 (pre0,r−pre1,r)−(pre0,l−pre1,l),记 di=pre0,i−pre1,i,原式为 dr−dl,相当于我们要求 l=1∑nr=1∑n∣dr−dl∣,根据 Sol. Prob. B 的办法排序后求值即可。
代码
#define int long long
void solve() {
int n;
cin >> n;
string s;
cin >> s;
int ans = 0;
for (int i = 1; i <= n; i++) {
ans += i * (n - i + 1);
}
vector<int> pre(n + 1);
for (int i = 0; i < n; i++) {
pre[i + 1] = pre[i] + (s[i] == '0' ? -1 : 1);
}
sort(pre.begin(), pre.end());
int tot = 0;
int sum = 0;
for (int i = 0; i <= n; i++) {
tot += i * pre[i] - sum;
sum += pre[i];
}
ans = (ans + tot) / 2;
cout << ans << "\n";
}