[置顶] 【专题】单调队列/斜率优化DP
一、单调队列
志愿者选拔 O(n)
struct STU{ char name[7]; int rp; }; int que[2111111]; int idx[2111111]; int main() { int T,head,tail; char gs[111]; scanf("%d",&T); while (T--) { int cas,cnt; head=tail=0; cas=cnt=0; while (scanf("%s",gs)) { if (strcmp(gs,"END")==0) break; if (strcmp(gs,"C")==0) { cnt++; STU tmp; scanf("%s%d",tmp.name,&tmp.rp); while (head<tail&&que[tail-1]<=tmp.rp) tail--; idx[tail]=cnt; que[tail++]=tmp.rp; } if (strcmp(gs,"G")==0) { cas++; if (idx[head]<=cas) head++; } if (strcmp(gs,"Q")==0) { if (head<tail) cout<<que[head]<<endl; else cout<<-1<<endl; } } } return 0; }
Sliding Window O(n)
#include <iostream> #include <cstdio> #include <vector> using namespace std; const int maxn=1111111; int a[maxn]; int que[maxn]; int idx[maxn]; int main() { int n,k; int head,tail,cas; while (~scanf("%d%d",&n,&k)) { for (int i=0;i<n;i++) scanf("%d",&a[i]); head=tail=cas=0; for (int i=0;i<n;i++) { while (head<tail&&que[tail-1]>=a[i]) tail--; idx[tail]=i; que[tail++]=a[i]; while (head<tail&&i-idx[head]>=k) head++; if (i>=k-1) cout<<que[head]<<" "; else if (i>=k-1&&i==n-1) cout<<que[head]; } cout<<endl; head=tail=cas=0; for (int i=0;i<n;i++) { while (head<tail&&que[tail-1]<=a[i]) tail--; idx[tail]=i; que[tail++]=a[i]; while (head<tail&&i-idx[head]>=k) head++; if (i>=k-1&&i<n-1) cout<<que[head]<<" "; else if (i>=k-1&&i==n-1) cout<<que[head]; } cout<<endl; } return 0; }
Max Sum of Max-K-sub-sequence O(n)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int a[411111]; int f[411111]; int que[1111111]; int pt[1111111]; int n,k; int T; int head,tail; int sum[411111]; int max_sum,start,end; int main() { scanf("%d",&T); while (T--) { memset(f,0,sizeof(f)); memset(que,0,sizeof(que)); memset(pt,0,sizeof(pt)); memset(sum,0,sizeof(sum)); scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i+n]=a[i]; } for (int i=1;i<=n+k;i++) { sum[i]+=sum[i-1]+a[i]; } //f[i]=max(sum[i]-sum[k]); head=tail=0; max_sum=start=end=-1e9; for (int i=1;i<=n+k;i++) { while ((head<tail)&&(i-pt[head]>k)) head++; while ((head<tail)&&(sum[i-1]<=que[tail-1])) tail--; que[tail]=sum[i-1],pt[tail++]=i-1; f[i]=sum[i]-que[head]; if (f[i]>max_sum) { max_sum=f[i]; start=pt[head]+1; end=i; } } if (start>n) start=start-n; if (end>n) end=end-n; printf("%d %d %d\n",max_sum,start,end); } return 0; }
二、单调队列dp
Trade O(n)
/** head-file **/ #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <vector> #include <queue> #include <stack> #include <list> #include <set> #include <map> #include <algorithm> /** define-for **/ #define REP(i, n) for (int i=0;i<int(n);++i) #define FOR(i, a, b) for (int i=int(a);i<int(b);++i) #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i) #define REP_1(i, n) for (int i=1;i<=int(n);++i) #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i) #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i) #define REP_N(i, n) for (i=0;i<int(n);++i) #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i) #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i) #define REP_1_N(i, n) for (i=1;i<=int(n);++i) #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i) #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i) /** define-useful **/ #define clr(x,a) memset(x,a,sizeof(x)) #define sz(x) int(x.size()) #define see(x) cerr<<#x<<" "<<x<<endl #define se(x) cerr<<" "<<x #define pb push_back #define mp make_pair /** test **/ #define Display(A, n, m) { \ REP(i, n){ \ REP(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } #define Display_1(A, n, m) { \ REP_1(i, n){ \ REP_1(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } using namespace std; /** typedef **/ typedef long long LL; /** Add - On **/ const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} }; const int MOD = 1000000007; const int INF = 0x3f3f3f3f; const long long INFF = 1LL << 60; const double EPS = 1e-9; const double OO = 1e15; const double PI = acos(-1.0); //M_PI; const int maxn=2222; int f[maxn][maxn]; int AP[maxn],BP[maxn],AS[maxn],BS[maxn]; int MaxP,W,T; /** f[i][j]=max(f[i-1][j],f[i-W-1][k]-AP[i]*(j-k),f[i-W-1][k]+BP[i]*(k-j)) f[i-W-1][k]-AP[i]*(j-k) =f[i-W-1][k]+AP[i]*k-AP[i]*j f[i-W-1][k]+BP[i]*(k-j) =f[i-W-1][k]+BP[i]*k-BP[i]*j **/ int que[maxn]; int idx[maxn]; int main() { int CAS; int head,tail,ans; scanf("%d",&CAS); while (CAS--) { scanf("%d%d%d",&T,&MaxP,&W); REP_1(i,T) { scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]); } REP_1(i,MaxP) f[0][i]=-INF; f[0][0]=0; ans=0; FOR_1(i,1,T) { FOR_1(j,0,MaxP) f[i][j]=f[i-1][j]; if (i-W-1<1) { FOR_1(j,0,AS[i]) f[i][j]=max(f[i][j],-AP[i]*j); continue; } head=tail=0; FOR_1(j,0,MaxP) { while (head<tail&&que[tail-1]<=f[i-W-1][j]+AP[i]*j) tail--; que[tail]=f[i-W-1][j]+AP[i]*j; idx[tail++]=j; while (head<tail&&j-idx[head]>AS[i]) head++; f[i][j]=max(f[i][j],que[head]-AP[i]*j); ans=max(ans,f[i][j]); } head=tail=0; DWN_1(j,MaxP,0) { while (head<tail&&que[tail-1]<=f[i-W-1][j]+BP[i]*j) tail--; que[tail]=f[i-W-1][j]+BP[i]*j; idx[tail++]=j; while (head<tail&&idx[head]-j>BS[i]) head++; f[i][j]=max(f[i][j],que[head]-BP[i]*j); ans=max(ans,f[i][j]); } } cout<<ans<<endl; } return 0; }
SubsequenceO(n)
/** head-file **/ #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <vector> #include <queue> #include <stack> #include <list> #include <set> #include <map> #include <algorithm> /** define-for **/ #define REP(i, n) for (int i=0;i<int(n);++i) #define FOR(i, a, b) for (int i=int(a);i<int(b);++i) #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i) #define REP_1(i, n) for (int i=1;i<=int(n);++i) #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i) #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i) #define REP_N(i, n) for (i=0;i<int(n);++i) #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i) #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i) #define REP_1_N(i, n) for (i=1;i<=int(n);++i) #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i) #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i) /** define-useful **/ #define clr(x,a) memset(x,a,sizeof(x)) #define sz(x) int(x.size()) #define see(x) cerr<<#x<<" "<<x<<endl #define se(x) cerr<<" "<<x #define pb push_back #define mp make_pair /** test **/ #define Display(A, n, m) { \ REP(i, n){ \ REP(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } #define Display_1(A, n, m) { \ REP_1(i, n){ \ REP_1(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } using namespace std; /** typedef **/ typedef long long LL; /** Add - On **/ const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} }; const int MOD = 1000000007; const int INF = 0x3f3f3f3f; const long long INFF = 1LL << 60; const double EPS = 1e-9; const double OO = 1e15; const double PI = acos(-1.0); //M_PI; const int maxn=110000; int a[maxn]; typedef pair<int,int> PII; deque<PII>q1,q2; int main() { int n,m,k; int ans,now; while (~scanf("%d%d%d",&n,&m,&k)) { ans=0; now=0; q1.clear(); q2.clear(); REP(i,n) { scanf("%d",&a[i]); while (!q1.empty()&&q1.back().first<=a[i]) q1.pop_back(); q1.push_back(mp(a[i],i)); while (!q2.empty()&&q2.back().first>=a[i]) q2.pop_back(); q2.push_back(mp(a[i],i)); while (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>k) { if (q1.front().second<q2.front().second) { now=q1.front().second+1; q1.pop_front(); } else { now=q2.front().second+1; q2.pop_front(); } } if (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>=m) ans=max(ans,i-now+1); } printf("%d\n",ans); } return 0; }
其他题目
MUTC8 E- One hundred layer 单调队列dp
三、斜率优化
MAX Average Problem O(n)
/** head-file **/ #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <vector> #include <queue> #include <stack> #include <list> #include <set> #include <map> #include <algorithm> /** define-for **/ #define REP(i, n) for (int i=0;i<int(n);++i) #define FOR(i, a, b) for (int i=int(a);i<int(b);++i) #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i) #define REP_1(i, n) for (int i=1;i<=int(n);++i) #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i) #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i) #define REP_N(i, n) for (i=0;i<int(n);++i) #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i) #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i) #define REP_1_N(i, n) for (i=1;i<=int(n);++i) #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i) #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i) /** define-useful **/ #define clr(x,a) memset(x,a,sizeof(x)) #define sz(x) int(x.size()) #define see(x) cerr<<#x<<" "<<x<<endl #define se(x) cerr<<" "<<x #define pb push_back #define mp make_pair /** test **/ #define Display(A, n, m) { \ REP(i, n){ \ REP(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } #define Display_1(A, n, m) { \ REP_1(i, n){ \ REP_1(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } using namespace std; /** typedef **/ typedef long long LL; /** Add - On **/ const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} }; const int MOD = 1000000007; const int INF = 0x3f3f3f3f; const long long INFF = 1LL << 60; const double EPS = 1e-9; const double OO = 1e15; const double PI = acos(-1.0); //M_PI; const int maxn=111111; int a[maxn]; int sum[maxn]; int que[maxn]; int head,tail; int getin() { char ch=' '; while (ch<'0'||ch>'9') ch=getchar(); int x=0; while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x; } double getup(int i,int j) { return sum[i]-sum[j]; } int getdown(int i,int j) { return i-j; } long long cross(int a,int b,int c) { long long x1=b-a; long long y1=sum[b]-sum[a]; long long x2=c-b; long long y2=sum[c]-sum[b]; return x1*y2-y1*x2; } int dbsearch(int l,int r,int i) { while (l<r) { int mid=(l+r)/2; if (cross(que[mid],que[mid+1],i)<0) r=mid; else l=mid+1; } return l; } int main() { int n,k; while (~scanf("%d%d",&n,&k)) { sum[0]=0; REP_1(i,n) { a[i]=getin(); sum[i]=sum[i-1]+a[i]; } head=tail=0; que[tail++]=0; double ans=0; FOR_1(i,k,n) { int j=i-k; while (head+1<tail&&cross(que[tail-2],que[tail-1],j)<0) tail--; que[tail++]=j; int tmp=dbsearch(0,tail-1,i); double f=double(sum[i]-sum[que[tmp]])/(i-que[tmp]); ans=max(ans,f); } printf("%0.2f\n",ans); } return 0; }
Print ArticleO(n)
/** head-file **/ #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <vector> #include <queue> #include <stack> #include <list> #include <set> #include <map> #include <algorithm> /** define-for **/ #define REP(i, n) for (int i=0;i<int(n);++i) #define FOR(i, a, b) for (int i=int(a);i<int(b);++i) #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i) #define REP_1(i, n) for (int i=1;i<=int(n);++i) #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i) #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i) #define REP_N(i, n) for (i=0;i<int(n);++i) #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i) #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i) #define REP_1_N(i, n) for (i=1;i<=int(n);++i) #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i) #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i) /** define-useful **/ #define clr(x,a) memset(x,a,sizeof(x)) #define sz(x) int(x.size()) #define see(x) cerr<<#x<<" "<<x<<endl #define se(x) cerr<<" "<<x #define pb push_back #define mp make_pair /** test **/ #define Display(A, n, m) { \ REP(i, n){ \ REP(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } #define Display_1(A, n, m) { \ REP_1(i, n){ \ REP_1(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } using namespace std; /** typedef **/ typedef long long LL; /** Add - On **/ const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} }; const int MOD = 1000000007; const int INF = 0x3f3f3f3f; const long long INFF = 1LL << 60; const double EPS = 1e-9; const double OO = 1e15; const double PI = acos(-1.0); //M_PI; /** f[i]=min( f[j]+(sum[i]-sum[j])^2+M ) y为f[j]+sum[j]^2,x为2*sum[j],斜率为sum[i],截距为f[i] **/ const int maxn=550000; int n,m; int a[maxn]; int f[maxn]; int que[maxn]; int head,tail; int sum[maxn]; int gety(int j){return f[j]+sum[j]*sum[j];} int getx(int j){return 2*sum[j];} int dp_sol(int i,int j){return f[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;} bool cmp_idx(int i,int j,int k) { return (gety(i)-gety(j))*(getx(j)-getx(k))<=(gety(j)-gety(k))*(getx(i)-getx(j)); } int main() { while (~scanf("%d%d",&n,&m)) { memset(f,0,sizeof(f)); sum[0]=0; REP_1(i,n) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } head=tail=0; que[tail++]=0; f[0]=0; for (int i=1;i<=n;i++) { while (tail-head>1&&dp_sol(i,que[head])>=dp_sol(i,que[head+1])) head++; f[i]=dp_sol(i,que[head]); while (tail-head>1&&cmp_idx(i,que[tail-1],que[tail-2])) tail--; que[tail++]=i; } cout<<f[n]<<endl; } return 0; }
其他题目
Codeforces
Round #189 (Div. 2) 解题报告
四、BST解决不单调的dp问题