1. 程式人生 > >bzoj 4990 [USACO17FEB] Why Did the Cow Cross the Road II P (樹狀數組優化DP)

bzoj 4990 [USACO17FEB] Why Did the Cow Cross the Road II P (樹狀數組優化DP)

upd 如果 直接 get-data clu http min fine long

題目大意:給你兩個序列,你可以兩個序列的點之間連邊

要求:1.只能在點權差值不大於4的點之間連邊

2.邊和邊不能相交

3.每個點只能連一次

技術分享圖片表示第一個序列進行到 i,第二個序列進行到 j,最多連的邊數,容易得到方程:

不連邊:技術分享圖片

連邊:技術分享圖片

實際是這樣的,每個位置如果想連邊,就要從能連邊的位置之前找最大值,即技術分享圖片

直接轉移不可取,由於最多只從9個位置轉移,我們可以縮減一維,用技術分享圖片記錄b序列進行到位置 j 的最大連邊數,再用樹狀數組維護技術分享圖片的最大前綴和方便轉移

 1 #include <bits/stdc++.h>
 2 #define N 200100
 3 #define ll long long  
 4
using namespace std; 5 6 int n,ans; 7 int a[N],b[N],hx[N],f[N],s[N]; 8 void update(int x,int w) {for(int i=x;i<=n;i+=(i&(-i))) {s[i]=max(s[i],w);}} 9 int query(int x) {int ans=0; for(int i=x;i>0;i-=(i&(-i))) {ans=max(ans,s[i]);} return ans;} 10 11 int main() 12 { 13 //freopen("Testdata.in","r",stdin);
14 scanf("%d",&n); 15 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 16 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 17 for(int i=1;i<=n;i++) hx[b[i]]=i; 18 for(int i=1;i<=n;i++) 19 { 20 for(int j=max(1,a[i]-4);j<=min(n,a[i]+4);j++) 21 f[hx[j]]=query(hx[j]-1
); 22 for(int j=max(1,a[i]-4);j<=min(n,a[i]+4);j++) 23 update(hx[j],f[hx[j]]+1); 24 } 25 printf("%d\n",query(n)); 26 return 0; 27 }

bzoj 4990 [USACO17FEB] Why Did the Cow Cross the Road II P (樹狀數組優化DP)