51nod 1624 STL妙用+二分

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1624

这是算法马拉松一道题。当时想法方向是正确的可惜没有想到STL。

题意3*n的矩阵。。要走出一条取余最大路。。

看到3肯定是在这里做文章。。那么可以枚举第一行二分剩下的嘛。。

到这里思路都很清晰,但是考虑到如果不删除(删除当前节点不合法的走法,移动一下删一个)的话,二分就结果不一定正确了。。这就十分尴尬

赛后看题解可以 multiset来删除,当然也可以map了。。。这里就是经验的问题了


二分时候要注意一些地方,一个最优答案当然是靠近P-1了,那么枚举的x怎么靠近P-1呢,当然有两种方法,一是x+y靠近p-1,要么是x+y靠近2*p-1了。

然后在multiset里面二分即可。。

这里要学习stl的应用,自己根本没有领会到stl的精髓啊。。。蒟蒻加油!

#include <iostream>
#include <set>
#include <stdio.h>
#include <algorithm>
#include <fstream>
using namespace std;

const int maxn=100005;
long long n,p;
long long arr[3][maxn];
long long sum[3][maxn];
multiset<int> s;
int main()
{
    scanf("%d%d",&n,&p);
    for(int i=0;i<3;i++){
        for(int j=0;j<n;j++){
            scanf("%d",&arr[i][j]);
            arr[i][j]=arr[i][j]%p;
        }
    }
    sum[0][0]=arr[0][0]%p;
    sum[0][1]=arr[0][1]%p;
    sum[0][2]=arr[0][2]%p;
    for(int i=0;i<3;i++){
        for(int j=1;j<n;j++){
            sum[i][j]=(sum[i][j-1]+arr[i][j])%p;
        }
    }
    for(int j=0;j<n;j++){
        s.insert(-((sum[1][j]+sum[2][n-1]-sum[2][j]+arr[2][j]+p+p)%p));
    }
    int ans=0;
    int x;
    multiset<int>::iterator it;
    for(int i=0;i<n;i++){
        it=s.lower_bound(-(p-1-(sum[0][i]-sum[1][i]+arr[1][i]+p+p)%p));
        if(it!=s.end())
        x=(sum[0][i]-sum[1][i]+arr[1][i]-*it+p+p)%p;
        it=s.lower_bound(-(p+p-1-(sum[0][i]-sum[1][i]+arr[1][i]+p+p)%p));
        if(it!=s.end())
        x=max((sum[0][i]-sum[1][i]+arr[1][i]-*it+p+p)%p,(long long)x);
        s.erase(s.find(-((sum[1][i]+sum[2][n-1]-sum[2][i]+arr[2][i]+p+p)%p)));
        ans=max(ans,x);
    }
    printf("%d",ans);
    return 0;
}



你可能感兴趣的:(51nod 1624 STL妙用+二分)