MAC如何使用Docker 配置PHP + Nginx執行環境
阿新 • • 發佈:2022-04-02
第一眼拿到這題,想到的應該直接就是差分約束!不妨令 \(K=n+1\),對於每個條件(第 \(i\) 個點輸入是 \(j\))是這樣的約束關係:
\[a_j-a_i\le K(1) \] \[a_{j+1}-a_i\ge K+1(2) \]再補充上:
\[a_{i+1}-a_i \ge 0(3) \]按照以上三個條件連邊即可。於是你發現樣例就過了,提交發現居然 \(50\%\)。然後發現 SPFA 死了。以下是 Luogu \(48\) 分程式碼(通過 \(50\%\)):
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=5e5+5; const ll inf=100000000000000000; ll dis[N],v[2*N]; int vis[N],n,m,k; int cnt,nxt[2*N],t[2*N],h[2*N],num[2*N]; inline void add(int x,int y,int z) //x-y<=z { swap(x,y); t[++cnt]=y; v[cnt]=z; nxt[cnt]=h[x]; h[x]=cnt; } queue <int> q; void spfa(int s) { for (int i=1;i<=n;i++) dis[i]=inf,vis[i]=0; dis[s]=0,vis[s]=1,num[s]=1; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for (int i=h[u];i;i=nxt[i]) { if (dis[t[i]]>dis[u]+v[i]) { dis[t[i]]=dis[u]+v[i]; if (vis[t[i]]==0) { vis[t[i]]=1; num[t[i]]++; if (num[t[i]]>n) { printf("NO"); exit(0); } q.push(t[i]); } } } } } inline int read() { char C=getchar(); int F=1,ANS=0; while (C<'0'||C>'9') { if (C=='-') F=-1; C=getchar(); } while (C>='0'&&C<='9') { ANS=ANS*10+C-'0'; C=getchar(); } return F*ANS; } int main() { n=read(),k=n+1; for (int i=1;i<=n;i++) { int x=read(); if (x!=i) add(x,i,k); if (x!=n) add(i,x+1,-k-1); } for (int i=1;i<=n;i++) add(i,0,0); for (int i=1;i<n;i++) add(i,i+1,0); spfa(0); printf("%d\n",k); for (int i=1;i<=n;i++) printf("%lld\n",dis[i]+inf); return 0; }
因為存在負權邊,所以不能使用 Dij 等其他最短路演算法。那麼怎麼解決負權?
先把原序列切成幾段,每碰到一個 \(i=j_i\) 的就切一下。顯然段和段之間不影響。對於每一個段,我們再考慮分層。最後一個是第 \(0\) 層,其他的第 \(i\) 個就是 \(j_i\) 的層數再加一。
我們令第 \(i\) 層的初始權值為 \(-iK\)。這樣會發現,條件 \((1)\) 中的 \(i,j\) 必然隔一層,那麼 \(K\) 就消掉了。條件 \((2)\) 中 \(i,j+1\) 割一層或兩層,兩層的話就不用考慮,否則 \(K\) 也消掉了。條件 \((3)\) 對於同一層的照樣做就行了。
於是原來的條件的權值只有 \(0\)
記得把每個數改為非負整數,還有段和段之間的間隔要注意。
// By: Little09 // Problem: P8098 [USACO22JAN] Tests for Haybales G // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P8098 // Memory Limit: 256 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; #define ll long long const int N=5e5+5; const ll inf=100000000000000000; ll dis[N],v[2*N],k; int a[N]; bool used[N]; int n,m; int cnt,nxt[2*N],t[2*N],h[2*N],d[N]; inline void add(int x,int y,int z) //x-y>=z { swap(x,y); t[++cnt]=y; v[cnt]=z; nxt[cnt]=h[x]; h[x]=cnt; d[y]++; } queue<int>q; void topo(int s,int l,int r) { for (int i=l;i<=r;i++) dis[i]=0,used[i]=0; q.push(s); dis[s]=0; for (int i=l;i<=r;i++) if (d[i]==0) q.push(i); while (!q.empty()) { int u=q.front(); q.pop(); for (int i=h[u];i;i=nxt[i]) { d[t[i]]--; dis[t[i]]=max(dis[t[i]],dis[u]+v[i]); if (d[t[i]]==0) q.push(t[i]); } } } inline int read() { char C=getchar(); int F=1,ANS=0; while (C<'0'||C>'9') { if (C=='-') F=-1; C=getchar(); } while (C>='0'&&C<='9') { ANS=ANS*10+C-'0'; C=getchar(); } return F*ANS; } int deth[N]; void work(int l,int r,ll qwq) { deth[r]=0; for (int i=0;i<=cnt;i++) { nxt[i]=0,v[i]=0,t[i]=0; } for (int i=l;i<=r;i++) h[i]=0,d[i]=0; h[0]=0,d[0]=0; cnt=0; for (int i=r-1;i>=l;i--) deth[i]=deth[a[i]]+1; for (int i=l;i<r;i++) { if (deth[i]==deth[i+1]) { add(i+1,i,0); } } for (int i=l;i<r;i++) { add(i,a[i],0); if (a[i]+1<=r&&deth[a[i]+1]==deth[a[i]]) add(a[i]+1,i,1); } for (int i=l;i<=r;i++) add(i,0,0); topo(0,l,r); for (int i=l;i<=r;i++) dis[i]-=1ll*deth[i]*k; for (int i=r;i>=l;i--) dis[i]-=dis[l]; for (int i=l;i<=r;i++) dis[i]+=qwq; } int main() { n=read(),k=n+1; for (int i=1;i<=n;i++) a[i]=read(); int las=1; ll tmp=0; for (int i=1;i<=n;i++) { if (a[i]==i) { work(las,i,tmp+k+1); las=i+1,tmp=dis[i]; } } printf("%lld\n",k); for (int i=1;i<=n;i++) printf("%lld\n",dis[i]); return 0; }