Codeforces Gym 101234E Lines Game
2017-06-19 21:25
253 查看
可以发现,我们一定会选择i和pi都递增的若干个位置,而且一个方案合法的充要条件是对于任意两个相邻的选择i和j,不存在k满足i<k<j且pi<pk<pj。为了方便增加p0=0和pn+1=n+1两个位置,设dpi为最靠右的一个选择为i的最小花费,那么我们可以列出一个O(n2)的dp。
dpi=vi+maxi,j可以相邻dpj
这个dp可以用分治优化。考虑左边对右边的贡献,把每个位置按照pi递增的顺序加入,在左边维护一个i递减的单调栈用来更新答案【i递减是因为如果出现了i′<i且pi′<i′,i′不能用来更新答案】,在右边维护一个i递增的单调栈【i递增是因为如果出现了i′>i且pi′<i,那么i′对i和之后的元素都没有影响】。建立一棵关于pi的线段树,在左边用dp值进行单点修改,在右边在合法的区间内【即大于栈顶的pi】进行区间查询最小值更新答案。因为排序和线段树的复杂度都是O(nlogn),所以总的复杂度O(nlog2n)。
dpi=vi+maxi,j可以相邻dpj
这个dp可以用分治优化。考虑左边对右边的贡献,把每个位置按照pi递增的顺序加入,在左边维护一个i递减的单调栈用来更新答案【i递减是因为如果出现了i′<i且pi′<i′,i′不能用来更新答案】,在右边维护一个i递增的单调栈【i递增是因为如果出现了i′>i且pi′<i,那么i′对i和之后的元素都没有影响】。建立一棵关于pi的线段树,在左边用dp值进行单点修改,在右边在合法的区间内【即大于栈顶的pi】进行区间查询最小值更新答案。因为排序和线段树的复杂度都是O(nlogn),所以总的复杂度O(nlog2n)。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=200010,maxt=4000010,oo=2e9+1000; int n,a[maxn],v[maxn],dp[maxn],mn[maxt],f[maxn],g[maxn],s1[maxn],s2[maxn]; int cmp(int x,int y) { return a[x]<a[y]; } void modi(int u,int L,int R,int p,int x) { if (L==R) { mn[u]=x; return; } int mid=(L+R)/2; if (p<=mid) modi(u*2,L,mid,p,x); else modi(u*2+1,mid+1,R,p,x); mn[u]=min(mn[u*2],mn[u*2+1]); } int qry(int u,int L,int R,int l,int r) { if (l<=L&&R<=r) return mn[u]; int ret=oo,mid=(L+R)/2; if (l<=mid) ret=min(ret,qry(u*2,L,mid,l,r)); if (r>mid) ret=min(ret,qry(u*2+1,mid+1,R,l,r)); return ret; } void solve(int l,int r) { if (l==r) return; int mid=(l+r)/2,t1=0,t2=0; solve(l,mid); for (int i=l;i<=mid;i++) f[i]=i; for (int i=mid+1;i<=r;i++) g[i]=i; sort(f+l,f+mid+1,cmp); sort(g+mid+1,g+r+1,cmp); for (int i=l,j=mid+1;i<=mid||j<=r;) if (i<=mid&&(j>r||a[f[i]]<a[g[j]])) { while (t1&&s1[t1]<f[i]) { modi(1,0,n,a[s1[t1]],oo); t1--; } s1[++t1]=f[i]; modi(1,0,n,a[f[i]],dp[f[i]]); i++; } else { while (t2&&s2[t2]>g[j]) t2--; dp[g[j]]=min(dp[g[j]],qry(1,0,n,t2?a[s2[t2]]+1:0,a[g[j]])+v[g[j]]); s2[++t2]=g[j]; j++; } while (t1) modi(1,0,n,a[s1[t1--]],oo); solve(mid+1,r); } void build(int u,int L,int R) { mn[u]=oo; if (L==R) return; int mid=(L+R)/2; build(u*2,L,mid); build(u*2+1,mid+1,R); } int main() { //freopen("i.in","r",stdin); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) scanf("%d",&v[i]); n++; a =n; build(1,0,n); for (int i=1;i<=n;i++) dp[i]=oo; solve(0,n); printf("%d\n",dp ); }
相关文章推荐
- Codeforces Gym 100379I Move the queen to the corner! 威佐夫博弈变形 + 高精度
- CodeForces Gym 100685C Cinderella (水题)
- CodeForces Gym 101615简要题解
- Codeforces gym 100685 E
- Codeforces Gym 100338C Important Roads 最短路+Tarjan找桥
- Codeforces Gym 100733I The Cool Monkeys 拆点+最大流
- codeforces gym 100286 H - Hell on the Markets (贪心算法)
- Codeforces Gym 100341I Hungry Queen 2 Set水题
- Codeforces Gym - 101617A Ducks in a Row [DP]
- Codeforces Gym-101161E【LCA+主席树】
- 【Codeforces Gym 100228 - I】Graph Dp
- Codeforces Gym 100543G Virus synthesis
- Codeforces Gym 100269F Flight Boarding Optimization 树状数组维护dp
- Codeforces Gym 100623I Problem I. Important Wires
- [构造] Codeforces Gym 101190 NEERC 16 C. Cactus Construction
- CodeForcesGym 100733G No Negations
- Codeforces Gym 100015H Hidden Code(暴力)
- Codeforces Gym 100340A Cookies
- CodeForces GYM 101158D Hidden Anagrams hash+unordered_set
- CodeForces Gym 100989B LCS (B)