您的位置:首页 > 其它

CodeForces - 862E Mahmoud and Ehab and the function 二分(思维题)

2017-10-03 22:12 726 查看
传送门:Codeforces 862E

题意:给出长为n的a序列和长为m的b序列,求



.


的最小值,其中0 <= j <= m - n

还有q次操作,每次操作将a[l..r]区间内的数 + x, 每次操作后求一次f(j)的最小值

思路:容易得到无论a序列的数怎么变化,每个位置上的数的加减性质是不会变的,即奇数位置上的数一直是加,偶数位置上的减,因此我们将f(j)的值拆成a序列的贡献和b序列的贡献两部分,无论j怎么变化,a序列的贡献是不会变化的,

而当a[l..r]区间更新时,a序列的贡献变化只由l..r区间长度和l的位置决定,并且可以O(1)求出来。

下面考虑b序列的贡献,b序列对所有f(j)的贡献一共有m - n + 1 种,而这些种贡献都是由b序列中一个长度为n的连续子序列产生的,因此我们可以用滑动窗口的方式在O(m)的时间内求出所有种b的贡献。具体细节看代码。

求出b序列的所有贡献后,每次要输出结果的时候二分一个最接近a序列贡献值的数就好了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define pi acos(-1)
#define MAXN 100010
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
ll a[MAXN], b[MAXN], all;
int n, m, q;
vector<ll> sum;
ll get(int id)
{
if(id == m - n + 1) return fabs(all - sum[id - 1]);
if(id == 0) return fabs(all - sum[id]);
return min(fabs(all - sum[id]), fabs(all - sum[id - 1]));
}
int main()
{
ll tmp = 0, x;
cin >> n >> m >> q;
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]), all += (i & 1 ? a[i] : -a[i]);
for(int i = 1; i <= m; i++)
{
scanf("%lld", &b[i]);
if(i <= n) tmp += (i & 1 ? b[i] : -b[i]);
else{
tmp -= b[i - n];//这两步是思维点
tmp = -tmp + (n & 1 ? b[i] : -b[i]);//注意这里是判断n的奇偶
}
if(i >= n)
sum.push_back(tmp);
}
sort(sum.begin(), sum.end());
tmp = lower_bound(sum.begin(), sum.end(), all) - sum.begin();
printf("%lld\n", get(tmp));
int l, r;
while(q--)
{
scanf("%d %d %lld", &l, &r, &x);
if((r - l + 1) & 1){//修改a序列贡献
if(l & 1) all += x;
else all -= x;
}
printf("%lld\n", get(lower_bound(sum.begin(), sum.end(), all) - sum.begin()));
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: