分析
可以把它看成一个背包
下降就是01背包,上升就是完全背包,然后超过范围的取最大值,时间复杂度
O
(
n
m
)
O(nm)
O(nm)
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=10011;
int n,m,k,up[N],dw[N],ulm[N],dlm[N],is_tune[N],dp[N][N/5];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
signed main(){
n=iut(),m=iut(),k=iut();
for (rr int i=1;i<=n;++i) up[i]=iut(),dw[i]=iut(),ulm[i]=m+1,dlm[i]=0;
for (rr int i=1;i<=k;++i){
rr int x=iut(),l=iut(),r=iut();
is_tune[x]=1,dlm[x]=l,ulm[x]=r;
}
memset(dp,42,sizeof(dp));
for (rr int i=1;i<=m;++i) dp[0][i]=0;
for (rr int i=1;i<=n;++i){
for (rr int j=1+up[i];j<=m+up[i];++j)
dp[i][j]=min(dp[i][j-up[i]],dp[i-1][j-up[i]])+1;
for (rr int j=m+1;j<=m+up[i];++j) dp[i][m]=min(dp[i][m],dp[i][j]);
for (rr int j=1;j<=m-dw[i];++j) dp[i][j]=min(dp[i][j],dp[i-1][j+dw[i]]);
for (rr int j=1;j<=dlm[i];++j) dp[i][j]=dp[0][0];
for (rr int j=ulm[i];j<=m;++j) dp[i][j]=dp[0][0];
}
rr int ans=dp[0][0];
for (rr int i=1;i<=m;++i) ans=min(ans,dp[n][i]);
if (ans<dp[0][0]) return !printf("1\n%d",ans);
else{
rr int ii,flag=0; ans=0;
for (ii=n;ii>=1;--ii){
for (rr int j=1;j<=m;++j){
if (dp[ii][j]>=dp[0][0]) continue;
flag=1; break;
}
if (flag) break;
}
for (rr int i=1;i<=ii;++i) ans+=is_tune[i];
return !printf("0\n%d",ans);
}
}