51nod 1624 取余最短路(set)

题意:

佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和。

有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的娱乐值变为对p取模后的值,这让佳佳十分的不开心,因为她无法找到一条能使她得到最大娱乐值的路径了!

她发现这个问题实在是太困难了,既然这样,那就只在3*n的矩阵内进行游戏吧!

现在的问题是,在一个3*n的带权矩阵中,从(1,1)走到(3,n),只能往右往下移动,问在模p意义下的移动过程中的权总和最大是多少。

 

实际上路径总是第一行1-i,第二行i-j,第三行j-n.

考虑问题的补,先求出矩阵的总和%p,不妨设为sum,那么减去没有走过的格子总和%p,不妨设为val。

而这个val可以表示为两个数列的前缀和和后缀和的值之和,需要动态调整找到最大的方案,使用set可以达到这个目标。

时间复杂度O(nlogn).

 

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-8
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FDR(i,a,n) for(int i=a; i>=n; --i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
inline void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=100005;
//Code begin...

int a[4][N], inv1[N], inv2[N], sum1[N], sum2[N], n, p;
set<int>vv;
set<int>::iterator it;

void init(){
    FOR(i,1,n) inv1[i]=(inv1[i-1]+a[2][i])%p, sum2[i]=(sum2[i-1]+a[3][i])%p;
    FDR(i,n,1) inv2[i]=(inv2[i+1]+a[2][i])%p, sum1[i]=(sum1[i+1]+a[1][i])%p;
    FOR(i,0,n-1) inv1[i]=(inv1[i]+sum1[i+2])%p;
    FDR(i,n+1,2) inv2[i]=(inv2[i]+sum2[i-2])%p;
}
int main ()
{
    int sum=0, ans=0;
    n=Scan(); p=Scan();
    FOR(i,1,3) FOR(j,1,n) a[i][j]=Scan(), sum=(sum+a[i][j])%p;
    init();
    FDR(i,n-1,0) {
        vv.insert(inv2[i+2]);
        int val=(sum-inv1[i]+p+1)%p;
        it=vv.lower_bound(val);
        if (it==vv.end()) it=vv.begin();
        ans=max(ans,((sum-inv1[i]-*it)%p+p)%p);
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2017-07-17 21:01  free-loop  阅读(286)  评论(0编辑  收藏  举报