zoukankan      html  css  js  c++  java
  • 1624 取余最长路

    时间限制:1 秒 空间限制:131072 KB 分值: 40

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

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

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

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


    样例解释:

    移动的方案为“下下右”。

    Input
    单组测试数据
    第一行两个数n(1<=n<=100000),p(1<=p<=1000000000)。
    接下来3行,每行n个数,第i行第j列表示a[i][j]表示该点的权(0<=a[i][j]<p)。
    Output
    一个整数表示答案。
    Input示例
    2 3
    2 2
    2 2
    0 1
    Output示例
    2
    思路:二分;

    我们可以发现所有可能的路径都可以由两个拐点决定,所以最终的和可以这样,sum=ans[3][n]-ans[3][y-1]+ans[2][y]-ans[2][x-1]+ans[1][x];
    sum=((ans[3][n]-ans[3][y-1]+ans[2][y])%m+(ans[1][x]-ans[2][x-1])%m)%m;
    ans为每行的前缀和;
    那么我们重小到大枚举y,然后将当前的(<=y)下标的(ans[1][x]-ans[2][x-1])%m)%m加入set,然后二分查找(m-ans[3][n]-ans[3][y-1]+ans[2][y])%m;
    因为,set中的数<=m-1;并且按升序排列,我们在set中找m-(ans[3][n]-ans[3][y-1]+ans[2][y])%m这个的加上(ans[3][n]-ans[3][y-1]+ans[2][y])再对m取余为0;是最小的
    我们先来看,假设我们有一个数tt,在m的完全省余系中,我们要找一个和他之和对m取余为0的数,下面我们要证明这个数是唯一的,假设存在两个数和他和模m为0;(x1+tt)%m==(x2+tt)%m;
    那么有x2-x1=km;由于-1<x1<m-1&&-1<x2<m-1;那么只能k=0,即x2=x1;
    由上结论,我们可以知道,在set中要么有一个要么没有我们要找的数,记为cnt;
    那么我们用lower_bound找到<=cnt且最接近他的数,如果有的话,他左边一个数并且做边有数,与(ans[3][n]-ans[3][y-1]+ans[2][y])%m和对m取模与
    set中的最后一个与(ans[3][n]-ans[3][y-1]+ans[2][y])%m的和对m取模比较,取大的。因为从左到模0处去和上面(ans[3][n]-ans[3][y-1]+ans[2][y])%m和对m取模的结果递增,
    重模0处到最后也是递增,模0处是最小的;
    那么没有模0处则当前的和最后的比较就行。
    复杂度(nlogn)
     1 #include<stdio.h>
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<string.h>
     5 #include<queue>
     6 #include<stack>
     7 #include<map>
     8 #include<math.h>
     9 #include<set>
    10 using namespace std;
    11 typedef long long LL;
    12 LL ans[5][100005];
    13 set<LL>G;
    14 set<LL>::iterator it;
    15 int main(void)
    16 {
    17     int i,j,k;
    18     LL n,m;
    19     memset(ans,0,sizeof(ans));
    20     scanf("%lld %lld",&n,&m);
    21     for(i=1; i<=3; i++)
    22     {
    23         for(j=1; j<=n; j++)
    24         {
    25             scanf("%lld",&ans[i][j]);
    26             ans[i][j]+=ans[i][j-1];
    27         }
    28     }
    29     LL maxx=0;
    30     int flag=0;
    31     for(i=1; i<=n; i++)
    32     {
    33         LL sum=(ans[3][n]+ans[2][i]-ans[3][i-1])%m;
    34         LL nn=m-sum;
    35         nn=(nn%m+m)%m;
    36         G.insert(((ans[1][i]-ans[2][i-1])%m+m)%m);
    37         it=G.lower_bound(nn);
    38         if(it!=G.begin())
    39             it--;
    40         {
    41             LL ak=((*it+sum))%m;
    42             it=G.end();it--;
    43             LL uu=*it;
    44             LL sk=(uu+sum)%m;
    45             if(sk>ak)
    46             {
    47                 ak=sk;
    48 
    49             }maxx=max(maxx,ak);
    50         }
    51         if(flag)
    52             break;
    53     }
    54     printf("%lld
    ",maxx);
    55     return 0;
    56 }
    油!油!you@
  • 相关阅读:
    13/6/21 Hella Intern Interview
    【ToReadList】六种姿势拿下连续子序列最大和问题,附伪代码(以HDU 1003 1231为例)(转载)
    【算法】[leetcode] permutations的讨论(转载)
    【算法】leetcode之 Palindrome Partitioning I&II(转载)
    【C++】从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法
    【C++】STL :栈
    【算法】逆波兰表达式
    【C++】STL,vector容器操作
    【LINUX】降级安装低版本GCC,G++
    【NS2】在linux下安装低版本GGC
  • 原文地址:https://www.cnblogs.com/zzuli2sjy/p/5477512.html
Copyright © 2011-2022 走看看