题目看这里
走的过程必然是这样的:从pos[1][1]走到pos[1][x]以至于pos[2][x],再走到pos[2][y]以至于pos[3][y],最后从pos[3][y]走到pos[3][n]。留意,这里x<=y。
假设第i层的前j项和为sum[i][j],其中i∈[1,3],j∈[1][n]。
那么这样一条转折点为x和y的路径所得的值为:
ans=sum[1][x]+(sum[2][y]-sum[2][x-1])+(sum[3][n]-sum[3][y-1])
把这个式子调整一下:
令①=sum[1][x]-sum[2][x-1];②=sum[2][y]-sum[3][y-1]+sum[3][n]
ans=①+②
相当于把x和y进行了分离,于是我们可以把①用set进行存储用以查询,穷举②。
穷举②的每一项的时候,set里有许多的①,那么哪一项才是好的呢?因为要mod P,因为所有元素都属于[0,P-1],所以:
要么让①+②最接近P,要么让①+②最接近2P,这样一模剩下来的才大。故而:
情况1:找<(p-②),且最接近这个值的,这样加起来会和会最接近P
情况2:情况1不存在,比如说set里的数都>=(p-②),那么直接找set里最大的那个就行。因为这样①+②能越过P之后尽可能往前走,使得数更大。
这里注意2个地方:
1:相减的地方可能产生负数,+P来调一下
2:这里的X是<=Y的,所以不能先把所有的①放进set再枚举②。得放一个①,②从前面的①构成的set里找。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowb lower_bound
const int maxN = 1e5 + 5;
ll N, P, sum[4][maxN];
set<ll> st;
int main() {
scanf("%lld%lld", &N, &P);
ll t;
for (int i = 1; i <= 3; ++i) {
sum[i][0] = 0;
for (int j = 1; j <= N; ++j) {
scanf("%lld", &t);
sum[i][j] = (sum[i][j - 1] + t) % P;
}
}
st.clear();
ll ans = 0;
for (int y = 1; y <= N; ++y) {
st.insert((sum[1][y] - sum[2][y - 1] + P) % P);
ll cur = (sum[2][y] - sum[3][y - 1] + sum[3][N] + P) % P;
t = P - cur;
set<ll>::iterator it = st.lowb(t);
if (it != st.begin())
ans = max(ans, (*(--it) + cur) % P);
else
ans = max(ans, (*(--st.end()) + cur) % P);
}
printf("%lld\n", ans);
return 0;
}
网友评论