XMOJ3376 结界
很憨憨的题,想复杂了,是这场比赛四道题中难度第二的,可却是我唯一没做出来的题,挡了我的AK路。(发怒)(难得过一次最难题)
题目大意
有一个环,第 i i i 个位置上有 a i a_i ai 个物品,定义一次操作为将一个位置上的一个物品移动到其相邻两个位置之一,求最少的操作次数使得第 i i i 个位置上有 b i b_i bi 个物品。
n ≤ 1 0 5 n≤10^5 n≤105, a , b ≤ 1000 a,b≤1000 a,b≤1000。
题解
先讲讲我赛时磕这题的心路历程。读完题发现 a , b a,b a,b 范围不大,所以一直在把复杂度往 a , b a,b a,b 上靠,然后一直往 dp 那个方向想,然后就憨完了。看了题解才发现很不牛,感觉如果 a , b a,b a,b 范围改成 1 0 9 10^9 109 赛时应该就会做了……
先考虑如果是一条链怎么做,很显然是贪心的去搞他,对于每个位置若是 a a a 比 b b b 大就把多余部分弄出来,若是少就把多出来的部分搞进去。统计答案时只需要算一下每条边需要经过几个物品即可。(以上便是我赛时想出来的部分和正解的交集。)
再考虑变成环,其实也就是往1和n之间加了条边,我们假设这条边经过了 x x x 个物品(为正则从1到n方向,否则从n到1方向),那么1的物品数量就变成了 a 1 − x a_1-x a1−x,1还需要的物品数量就是 b 1 − a 1 + x b_1-a_1+x b1−a1+x(为正则给出去)。而此时只有2连向1的边能移动物品(因为1到n的边通过的物品数量已经被钦定好了),所以这条边所需要通过的物品数量就是 b 1 − a 1 + x b_1-a_1+x b1−a1+x,然后2的物品数变成了 a 2 − b 1 + a 1 − x a_2-b_1+a_1-x a2−b1+a1−x,2还需要的物品数量就是 b 2 − a 2 + b 1 − a 1 + x b_2-a_2+b_1-a_1+x b2−a2+b1−a1+x,而此时只有3连向2的边能移动物品,所以这条边通过的物品数量就是 b 2 − a 2 + b 1 − a 1 + x b_2-a_2+b_1-a_1+x b2−a2+b1−a1+x……以此类推,我们可以算出每条边通过的物品数。
最后的答案就是每条边通过的物品数绝对值相加,发现每条边通过的物品数除了 x x x 以外都是一个常量,不妨设为 c i c_i ci,那么结果就是 ∑ ∣ c i + x ∣ = ∑ ∣ c i − ( − x ) ∣ \sum |c_i+x|=\sum |c_i-(-x)| ∑∣ci+x∣=∑∣ci−(−x)∣,然后就是很经典的问题,直接取中位数即可。
复杂度可以 O ( n ) O(n) O(n),但取中位数我为了方便用了 sort 所以是 O ( n l o g n ) O(nlogn) O(nlogn)。
Code
代码巨简洁。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
int n,m,a[N],b[N],c[N];
ll ans;
int main(){
freopen("border.in","r",stdin);
freopen("border.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i],&b[i]);
c[1]=0;
for(int i=2;i<=n;i++)
c[i]=c[i-1]+b[i-1]-a[i-1];
sort(c+1,c+1+n);
if(n&1) m=c[(n+1)/2];
else m=(c[n/2]+c[n/2+1])/2;
for(int i=1;i<=n;i++)
ans+=abs(c[i]-m);
printf("%lld",ans);
return 0;
}
有一种输给了绿题的耻辱感,所以遇到这种数据范围开小了被误导的题有什么解决办法吗?