单调性

单调队列优化dp+决策单调性——poj3017好题

无人久伴 提交于 2020-03-17 17:49:32
/* dp[i]表示前i个数的最优解 dp[i]=min{ dp[j]+max[j+1,i] },sum[i]-sum[j]<=M 使用决策单调性:显然dp[i]是单调递增的 那么维护一个区间[j+1,i]关于a的递减单调队列q 对于a[q[1]]可以控制的决策范围是[j+1,q[1]],又因为决策单调性,所以这一段区间的最优解就是dp[j+1]+a[q[1]] 同理,遍历整个队列,可得后面每一段的最佳决策 */ #include<iostream> #include<queue> #include<cstdio> using namespace std; #define ll long long #define N 200005 ll n,M,a[N],sum[N],dp[N]; int main(){ cin>>n>>M; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++)if(a[i]>M){ puts("-1");return 0; } memset(dp,0x3f,sizeof dp);dp[0]=0; deque<int>q; deque<int>::iterator it,itt; int pos=1;

决策单调性优化dp

回眸只為那壹抹淺笑 提交于 2020-02-25 22:17:56
概述 决策单调性用于优化一类 \(1D1D\) 涉及高次,或复杂 二维 \(dp\) 具体来说,决策单调性指决策状态与决策点间的单调关系,具象化的证明和运用体现就是四边形不等式 四边形不等式 \(\mathtt{\color{red}Achen}\) 说这个东西没有必要因为决策单调性确实有更简便更数学化的证明食用方法,但在实战中,四边形不等式快速辅佐/证伪猜想非常套路 基本概念 首先,定义一维dp决策单调性如下 另 \(s_i\) 表示 \(dp_i\) 取到的最优决策点 \(j\) ,当 \(a<b\) 时总有 \(s_a\leqslant s_b\) 定义区间单调性如下: 当 \(a\leqslant b\leqslant c\leqslant d\) 时,若 \(w\left(b,c\right)\leqslant w\left(a,d\right)\) ,则称 \(w\) 满足区间单调性 即 被包含比包含优 同时定义四边形不等式如下: 当 \(a\leqslant b\leqslant c\leqslant d\) 时,若 \(w\) 满足如下式子,则称 \(w\) 满足四边形不等式: \(w\left(a,c\right)+w\left(b,d\right)\leqslant w\left(b,c\right)+w\left(a,d\right)\) 即 交错比嵌套优

决策单调性

独自空忆成欢 提交于 2020-01-22 23:11:27
决策单调性:状态转移的最优决策点单调递增 可以用二分栈或者分治来实现 二分栈中存有三元组 \((l,r,pos)\) , \(l\) 代表决策的作用起点, \(r\) 代表决策的作用终点, \(pos\) 是决策点的位置 若当前状态 \(i\) 已经不在栈头决策点的范围内,就弹出栈头 若位置为 \(i\) 的决策优于栈尾的决策,才进行下一步操作,来更新决策 若新决策点的作用范围覆盖了旧决策点,就弹出栈尾 若栈空了,就直接加入新决策点,说明其当前是最优的,否则就通过在旧决策点的范围内二分,来确定旧决策点的终点和新决策的的起点 时间复杂度 \(O(n\ log\ n)\) 诗人小G : \(f_i=\min\limits_{j=0}^{i-1}\ f_j+|s_i-s_j-L-1|^P\) \(code:\) ld calc(int i,int j) { return f[j]+qp((ld)abs(s[i]-s[j]-l-1),p); } int find(node t,int x) { int l=t.l,r=t.r,pos=t.pos; while(l<=r) { int mid=(l+r)>>1; if(calc(mid,x)<=calc(mid,pos)) r=mid-1; else l=mid+1; } return l; } ...... q[h=t=1]=(node)

Hello 2020 B - New Year and Ascent Sequence (容斥)

╄→гoц情女王★ 提交于 2020-01-19 07:05:57
🎂 🎂 🎂 1,需要寻找的方案出现:满足 A条件 or B条件 均可计算在内,而有可能存在方案符合多个(A and B)条件(可能会计算重复)的情况下考虑 容斥 2,求满足最大值小于最小值的对数,利用单调性:如果最大值maxv,最小值minv集合有序,对于i<j如果某minv[k]>=maxv[j] 则 一定存在minv[k]>maxv[i],(即 当前数组不符合条件的对数是递增的 ) 3,只有 原数组降序 的情况会出现找不到i<j&&a[i]<a[j] signed main ( ) { int n ; cin >> n ; vector < int > mxv , mnv ; rep ( i , n ) { int k ; cin >> k ; vector < int > x ( k ) ; cin >> x ; reverse ( all ( x ) ) ; if ( is_sorted ( all ( x ) ) ) mxv . push_back ( x . back ( ) ) , mnv . push_back ( x [ 0 ] ) ; } sort ( all ( mxv ) ) ; sort ( all ( mnv ) ) ; ll ans = 1ll * n * n ; int r1 = mxv . size ( ) - 1 , r2 = mnv .

cf1276C——单调性分析,思维

拟墨画扇 提交于 2019-12-28 13:14:12
/* 假设row<=col,先求出面积最大的矩阵的(row,col),再去考虑往里面填数 当前行是row时,这个矩阵里最多容纳同一个数row次, 将数统计之后,按出现次数排序,再从大到小枚举row,通过每个数的出现次数,算出此时最大的col 记录下最大的row和col,然后进行填数,填数时同一个数斜着填即可 */ #include<bits/stdc++.h> using namespace std; #define N 400005 #define ll long long int sum[N],n,a[N],cnt; map<int,int>mp; struct Node{int v,cnt;}p[N]; int cmp(Node &a,Node &b){return a.cnt<b.cnt;} int bin_find(int row){//找到最后一个<=row的位置 int L=0,R=cnt,ans=0,mid; while(L<=R){ mid=L+R>>1; if(p[mid].cnt<=row) ans=mid,L=mid+1; else R=mid-1; } return ans; } int ma[N],R,C; inline int id(int i,int j){return C*(i-1)+j;} stack<int>stk; void solve(){

单调队列

我与影子孤独终老i 提交于 2019-12-17 15:55:44
单调队列,顾名思义就是具有单调性的队列O(∩_∩)O~,一般的队列只能从队尾入队、队首出队;为了保持单调队列的单调性,单调队列除具有这两种性质外,还可以从队尾出队。 以单增的单调队列为例,当元素t要入队时,先要从队尾依次弹出所有>=t的元素,再将t加在队尾。 举个例子,如果序列:1 3 -1 -3 10要构成单调队列, 先将元素“1”放入队列中,以初始化队列, 接着元素“3”要入队,队尾元素“1”比“3”小,因此“3”可以直接入队,队列变为1 3, 接着“-1”要入队,从队尾依次弹出元素“3”“1”后将“-1”入队,队列变为-1, 同理“-3”入队后,队列变为-3, “10”入队后,队列变为-3 10 单调队列有什么用呢?看一道例题:(poj2823) 给定含有n个元素的无序序列a[],和一个整数k,要求求出a[]中每连续k个元素组成的序列中的最小值(或最大值),这样的值可能有1个或n-k+1个。 比较简单的方式,是每次都将k个数的最值找出,具有O(K*n)的时间复杂度。但如果用单调队列的话,我们可以在O(n)的时间内求解,原因是每个元素最多入队一次、出队一次。 要解决该题,我们还要记录每个元素在原序列中的位置p,每次只需从队首开始找到跟当前元素a[i]距离不大于k的元素(即是i-p+1<=k)输出即可。 一、 什么是单调(双端)队列 单调队列,顾名思义,就是一个元素单调的队列

决策单调性优化DP+分治优化决策单调性

大兔子大兔子 提交于 2019-12-07 17:53:27
前言 本来这篇已经写了 \(\frac{2}{3}\) 了 然后我关机时忘保存了。。。 华丽的分割线 决策单调性优化 \(DP\) 对于类似于 \[dp[i][j]=max/min(dp[k - 1][j - 1] + count(k,i))\] 不妨设 当 最后一次 \(max/min\) 更新时 \[f(i,j)=k\] 若有 \[\forall i,j\in[1,n],s.t. i < j \Rightarrow f(i,k)<=f(j,k)\] 我就可以称她具有决策单调性 例题 [HNOI2008]玩具装箱TOY 题意我就不概括了 据题 容易推出状态方程 \[dp[i]=min(dp[j-1]+count(i,j))\] 凭感觉 是具有决策单调性的 其实可以证明 不过我太菜了 不会 既然决策具有单调性 那么对于每一个决策点 我们可以拿出一个决策区间 用一个双端队列维护 决策点 和 决策区间 在每一次循环前 把区间 \(.r<i\) 的舍去 然后再以当前点为决策点看是否能比队列中的对后面的贡献更小 既 while(l <= r&&dp[i] + count(q[r].l,i) <= dp[q[r].pos] + count(q[r].l,q[r].pos)) r--; 注意 \(while\) 结束后还要特判一下 \[dp[i] + count(q[r].l,i) <= dp

【dp】一题 决策单调性优化dp 斜率优化

爷,独闯天下 提交于 2019-12-06 20:16:40
luoguP3515 已知一个长度为n的序列a1,a2,...,an。 对于每个1<=i<=n,找到最小的非负整数p满足: 对于任意的j, \(a_j\) <= \(a_i\) +p- \(\sqrt{|i-j|}\) n<=5* \(10^5\) 考虑j<i的方面 则需满足对j<i a[j]<=a[i]+p- \(\sqrt{i-j}\) , 即:a[j]+ \(\sqrt{i-j}\) <=a[i]+p 设g是决策点 即 a[g]+ \(\sqrt{i-g}\) <=a[i]+p这个g是求出 \(ans_p\) 的那个g 所以 对于任意正整数k 有 a[g-k]+ \(\sqrt{i-(g-k)}\) <=a[g]+ \(\sqrt{i-g}\) 所以: 那么对于 询问的点i+1 有: a[g-k]+ \(\sqrt{i+1-(g-k)}\) <a[g]+ \(\sqrt{i+1-g}\) 【1】 因为: \(\sqrt{i+1-(g-k)}\) - \(\sqrt(i-(g-k))\) < \(\sqrt{i+1-g}\) - \(\sqrt{i-g}\) 因为: 对于sqrt函数,数值越大 斜率越小,即是 数值越大 因变量+1增加的函数值越小 对于【1】有结论:i点的 所有g-k 均不是i+1的决策点 (因为‘<’,所以肯定在i+1时 g点比g-k优) 所以在j<i的条件下

关于二分栈优化DP算法的理解

不打扰是莪最后的温柔 提交于 2019-12-06 04:33:08
引入 二分栈主要用来优化满足决策单调性的DP转移式。 即我们设 \(P[i]\) 为 \(i\) 的决策点位置,那么 \(P[i]\) 满足单调递增的性质的DP。 由于在这种DP中,满足决策点单调递增,那么对于一个点来说,以它为决策点的点一定是一段连续的区间。 所以我们可以枚举以哪个点作为决策点,去找到它所对应的以它为决策点的区间。 考虑如何找到一个点的区间: 可以发现,在当前情况下(枚举到以某个点作为决策点的情况下),该点所对应的区间一定为[L,N].(L可能等于N+1) 那么我们可以用一个栈来存储区间[L,N]中的L,每次新枚举到一个决策点 \(i\) ,就用栈顶L判断,看L是用原决策点更优,还是用新决策点 \(i\) 更优。 因为满足决策单调性,所以若用新决策点更优的话,该L就没有意义了,就直接可以从栈顶弹出。 我们一直执行以上操作,直到遇到一个L的原决策点比新决策点 \(i\) 更优,那么说明这个L还是有意义的,所以不能弹。 然后我们就需要去二分一个点出来作为新的L,使得这个点右边的点以 \(i\) 为决策点更优,左边的点以 \(i\) 为决策点更劣。 以上就是二分栈的基本思路。 举个例子: 决策点: 1111111111 栈:1(1) 决策点: 111 2222222 栈:1(1) 4(2) 决策点: 111 22222 33 栈:1(1) 4(2) 9(3) 决策点:

单调性 - 51Nod 1383(整数分解为2的幂), 2019.10.25 T1

纵饮孤独 提交于 2019-12-03 11:54:55
题面 51Nod 1383 解法 1 设 \(n\) 的划分数为 \(f(n)\) , 则 \[f(n)= \begin{cases} 1 & n=1\\ f(n-1) & n\equiv 1\pmod{2}, n\ne 1 \\ f(n-1)+f(\lfloor n/2\rfloor) & n\equiv 0\pmod{2} \end{cases}\] 证明略. 时间复杂度 \(O(n)\) , 空间复杂度 \(O(n)\) . 测评时耗时 \(3.502647\ \text{ms}\) , 占用 \(3952\ \text{KiB}\) . 程序 #include <iostream> #include <cstring> using namespace std; #define MAXN 1000050 #define MOD 1000000007 int d[MAXN]; void calcdp(int m) { d[1] = 1; for (int i = 2; i <= m; i++) if (i % 2) d[i] = d[i - 1]; else d[i] = (d[i - 1] + d[i / 2]) % MOD; } int main() { int m; cin >> m; calcdp(m); cout << d[m] << endl; return 0;