• 【动态规划杂谈】


    前言

    最后一块了,这周写完就去板刷联合省选

    单调队列

    [POI2014]PTA-Little Bird

    [POI2014]PTA-Little Bird
    没什么好说的,决策单调性考虑一下就好了

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 2000000
    
    ll n,q;
    ll v[N];
    ll QWQ[N],s,t,ans[N];
    
    void del(ll k){
    	QWQ[1] = 1,ans[1] = 0;
    	s = 1,t = 1;
    	for(int i = 2;i <= n;++i){
    		ll l = std::max((ll)1,i - k);
    		while(QWQ[s] < l && (s <= t)){s ++;}
    		ans[i] = ans[QWQ[s]] + (v[i] >= v[QWQ[s]]);
    		while((ans[QWQ[t]] > ans[i] || (ans[QWQ[t]] == ans[i] && v[QWQ[t]] <= v[i])) && t >= s)
    		t -- ;
    		QWQ[++t] = i;
    	}
    	std::cout<<ans[n]<<std::endl;
    }
    
    int main(){
    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i)
    		scanf("%lld",&v[i]);
    	scanf("%lld",&q);
    	while(q -- ){
    		ll k;
    		scanf("%lld",&k);
    		del(k);
    	}
    }
    

    斜率优化

    [SDOI2016]征途

    [SDOI2016]征途
    仔细的分析一下题目
    其实要求的答案是这个
    \(m\sum{x_i ^ 2} - (\sum{x_i}) ^ 2\)
    此时我们显然只需要考虑使\(\sum{x_i^2}\)最小
    \(f_{i,j}\)为到第\(i\)个数,划分了\(j\)段的最小值,那么\(f_{i,j} = min(f_{k,j - 1} + (sum_i - sum_k) ^ 2)\)
    看到后面这个柿子
    自然看到了斜率优化

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 4000
    
    ll n,m;
    ll v[N],f[N][N],s[N];
    ll head,end;
    ll QWQ[N];
    
    ll k;
    
    inline ll a(ll x){return s[x];}
    inline ll Y(ll x){return f[x][k - 1] + s[x] * s[x];}
    inline ll X(ll x){return s[x];}
    inline double solve(ll x,ll y){return (1.0 * Y(y) - Y(x)) / (1.0 * X(y) - X(x));}
    
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i = 1;i <= n;++i)
    	scanf("%lld",&v[i]),s[i] = s[i - 1] + v[i];
    	for(int i = 1;i <= n;++i)
    	f[i][1] = s[i] * s[i];
    	for(k = 2;k <= m;++k){
    		head = end = 1;
    		QWQ[head] = 0;
    		for(int i = 1;i <= n;++i){
    			while(head < end && solve(QWQ[head],QWQ[head + 1]) < 2 * s[i]) ++ head;
    			f[i][k] = f[QWQ[head]][k - 1] + (s[i] - s[QWQ[head]]) * (s[i] - s[QWQ[head]]);
    			while(head < end && solve(QWQ[end - 1],QWQ[end]) > solve(QWQ[end],i))--end;
    			QWQ[++end] = i;
    		}
    	}
    	std::cout<<m * f[n][m] - s[n] * s[n]<<std::endl;
    }
    

    [JSOI2011] 柠檬

    不太会,先鸽着,大概有一点想法就是两端的颜色一样,用颜色来计算。

    决策单调性

    [POI2011]Lightning Conductor

    [POI2011]Lightning Conductor
    这。。
    是一道我看错题目,然后推到自闭的题
    我疯狂推,发现了不存在单调性。。。。。
    大概是这么个意思吧
    \(p_i = max(a_j - a_i + \sqrt{\vert(i - j)\vert)\)
    (借一下你谷神仙的图)
    我们看到,其实如果我们考虑从前往后,从后往前,那么我们不用考虑绝对值。
    那我们只考虑从前往后,那么对于每个点决策我们发现,必定是单调上升的。
    所以我们可以利用这个方法进行分治处理。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 5;
    
    int n, a[maxn]; double ans[maxn];
    
    double calc(int i, int j) {
        return a[j] - a[i] + sqrt((double)i - j);
    }
    void solve(int l, int r, int jl, int jr)
    {
        int m = l + r >> 1;
        int jp = jl; double jval = calc(m, jl), val;
        for (int j = jl; j <= jr && j <= m; j++) {
            val = calc(m, j);
            if (val > jval) jval = val, jp = j;
        }
        ans[m] = max(ans[m], jval);
        
        if (l < m) solve(l, m - 1, jl, jp);
        if (m < r) solve(m + 1, r, jp, jr);
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        solve(1, n, 1, n);
        reverse(a + 1, a + n + 1);
        reverse(ans + 1, ans + n + 1);
        solve(1, n, 1, n);
        for (int i = n; i >= 1; i--) printf("%d\n", (int)ceil(ans[i]));
        return 0;
    }
    

    数据结构维护

    [HEOI2016/TJOI2016]序列

    [HEOI2016/TJOI2016]序列
    \(DP\)柿子不再赘述,发现是一个三维偏序的转移,\(CDQ\)分治和各种嵌套数据结构都行,现在才发现,自己嵌套数据结构和可持久化可能跟没有学过一样
    借一下兔兔的\(CDQ\)代码
    我会补上的

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int MN = 100005;
    const int MC = 100000;
    
    int N, M;
    int A[MN], Mx[MN], Mn[MN];
    int f[MN], Ans;
    int p[MN];
    inline bool cmp1(int i, int j) { return Mx[i] < Mx[j]; }
    inline bool cmp2(int i, int j) { return A[i] < A[j]; }
    
    int B[MN];
    inline void Ins(int i, int x) { for (; i <= MC; i += i & -i) B[i] = max(B[i], x); }
    inline void Clr(int i) { for (; i <= MC; i += i & -i) B[i] = 0; }
    inline int Qur(int i) { int A = 0; for (; i; i -= i & -i) A = max(A, B[i]); return A;}
    
    void CDQ(int lb, int rb) {
    	if (lb == rb) {
    		f[lb] = max(f[lb], 1);
    		return;
    	}
    	int mid = lb + rb >> 1;
    	CDQ(lb, mid);
    	for (int i = lb; i <= rb; ++i)
    		p[i] = i;
    	sort(p + lb, p + mid + 1, cmp1);
    	sort(p + mid + 1, p + rb + 1, cmp2);
    	int j = lb;
    	for (int i = mid + 1; i <= rb; ++i) {
    		while (j <= mid && Mx[p[j]] <= A[p[i]]) {
    			Ins(A[p[j]], f[p[j]]);
    			++j;
    		}
    		f[p[i]] = max(f[p[i]], Qur(Mn[p[i]]) + 1);
    	}
    	for (int i = lb; i <= mid; ++i)
    		Clr(A[i]);
    	CDQ(mid + 1, rb);
    }
    
    int main() {
    	int x, y;
    	scanf("%d%d", &N, &M);
    	for (int i = 1; i <= N; ++i)
    		scanf("%d", &A[i]),
    		Mx[i] = Mn[i] = A[i];
    	for (int i = 1; i <= M; ++i)
    		scanf("%d%d", &x, &y),
    		Mx[x] = max(Mx[x], y),
    		Mn[x] = min(Mn[x], y);
    	CDQ(1, N);
    	for (int i = 1; i <= N; ++i)
    		Ans = max(Ans, f[i]);
    	printf("%d\n", Ans);
    	return 0;
    }
     
    
  • 相关阅读:
    django-rest-framework之基于类的视图
    django-rest-framework之请求与响应
    django-rest-framework之序列化
    Linux上安装二进制文件MySQL详解
    django-rest-framework快速入门
    初识RESTful
    layer弹出层详解
    Jquery.validate.js表单验证
    实习总结
    常见的攻击手段及其防御方式
  • 原文地址:https://www.cnblogs.com/dixiao/p/14571067.html
Copyright © 2020-2023  润新知