题解:P10978 Fence
HZEason_Ai · · 题解
题目传送门
说明
本题解默认读者掌握单调队列用法,如若不然,请转向 P2032 扫描。
Solution
先将所有工匠按
设
1.第
2.第
3.设
对于第三个转移展开后发现与
for(int i=1;i<=m;i++)
{
int h=0,t=0;
for(int j=1;j<=n;j++)
{
f[i][j]=max(f[i][j-1],f[i-1][j]);//前两种转移
if(j>=a[i].s+a[i].l) continue;//不可到达
while(h<=t&&q[h]+a[i].l<j) h++;//队首元素不合法
if(j<a[i].s)
{
while(h<=t&&f[i-1][q[t]]-q[t]*a[i].p<f[i-1][j]-j*a[i].p) t--;
q[++t]=j;
}
else f[i][j]=max(f[i][j],f[i-1][q[h]]+a[i].p*(j-q[h]));
//转移时,应满足j+a[i].s
}
}
因为每次决策时至多入队或出队一次,故转移复杂度为
AC代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define er puts("")
#define sc putchar(' ')
using namespace std;
const int N=1.6e4+5,M=1e2+5;
int q[N],f[M][N];
struct node{
int l,p,s;
}a[N];
bool cmp(node x,node y){return x.s<y.s;}
int read()
{
int x=0,a=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') a=-1;
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
return x*a;
}
void write(int x)
{
if(x<0) x*=-1,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
return;
}
signed main()
{
int n=read(),m=read();
for(int i=1;i<=m;i++)
a[i].l=read(),a[i].p=read(),a[i].s=read();
sort(a+1,a+1+m,cmp);//转化为线性DP
for(int i=1;i<=m;i++)
{
int h=0,t=0;
for(int j=1;j<=n;j++)
{
f[i][j]=max(f[i][j-1],f[i-1][j]);//前两种转移
if(j>=a[i].s+a[i].l) continue;//不可到达
while(h<=t&&q[h]+a[i].l<j) h++;//队首元素不合法
if(j<a[i].s)
{
while(h<=t&&f[i-1][q[t]]-q[t]*a[i].p<f[i-1][j]-j*a[i].p) t--;//保证单调
q[++t]=j;//入队
}
else f[i][j]=max(f[i][j],f[i-1][q[h]]+a[i].p*(j-q[h]));
//转移时,应满足j+a[i].s
}
}
write(f[m][n]);
return 0;
}