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).
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 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; }