zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    位运算
    方法重载
    基本数据类型与引用数据类型参数
    带返回值方法的定义格式
    return使用
    方法的通用格式
    方法定义的格式
    google chrome developer tools
    Skolelinux
    ajax
  • 原文地址:https://www.cnblogs.com/lishiyao/p/7197510.html
Copyright © 2011-2022 走看看