1. 程式人生 > >51nod 1624 取余最短路(set)

51nod 1624 取余最短路(set)

目標 while span lose gin 技術分享 putc inf end

題意:

佳佳有一個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

51nod 1624 取余最短路(set)