美文网首页
51nod 1624 取余最长路

51nod 1624 取余最长路

作者: fruits_ | 来源:发表于2018-08-21 20:07 被阅读0次

    题目看这里
    走的过程必然是这样的:从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;
    }
    

    相关文章

      网友评论

          本文标题:51nod 1624 取余最长路

          本文链接:https://www.haomeiwen.com/subject/ueqsiftx.html