题解 P1328 【生活大爆炸版石头剪刀布】
f(i,j)->f(i-1,j+Y[i-1])
->f(i-1,j-k\*X[i-1])+k,k>0且j-k\*X[i-1]>0
完全背包式优化:
f(i,j)->f(i-1,j-X[i-1])+1
->f(i,j-X[i-1])+1
->f(i-1,j+Y[i-1])
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
typedef short hd;
char * ptr=(char *)malloc(1000000);
int f[10001][1001];
inline void in(hd &x){
while(*ptr<'0'||*ptr>'9')++ptr;
x=0;
while(*ptr>47&&*ptr<58)x=x*10+*ptr++-'0';
}
int main(){
hd P[10000],down[10001],up[10001],X[10000],Y[10000],N,M,K,tmp,i,j;
int MAXN=2000000000;
freopen("birda.in","r",stdin);
freopen("birda.out","w",stdout);
//读入
fread(ptr,1,1000000,stdin);
in(N),in(M),in(K);
for(i=0;i<N;++i)in(X[i]),in(Y[i]);
for(i=0;i<=N;++i)up[i]=M+1;
for(i=0;i<K;++i)in(P[i]),in(down[P[i]]),in(up[P[i]]);
//初始化
sort(P,P+K);
memset(*f+1001,127,sizeof(f)-sizeof(int)*1001);
f[0][0]=MAXN;
//DP
for(i=1;i<=N;++i){
for(j=1;tmp=min((hd)(j+X[i-1]),M),j<=M;++j)f[i][tmp]=min(f[i][tmp],f[i-1][j]+1);
for(j=1;tmp=min((hd)(j+X[i-1]),M),j<M;++j)f[i][tmp]=min(f[i][tmp],f[i][j]+1);
for(j=M;j>Y[i-1];--j)f[i][j-Y[i-1]]=min(f[i][j-Y[i-1]],f[i-1][j]);
for(j=0;j<=down[i];++j)f[i][j]=MAXN;
for(j=up[i];j<=M;++j)f[i][j]=MAXN;
//判断当前列是否可达
j=1;
while(j<=M&&f[i][j]>=MAXN)++j;
if(j>M)break;
}
if(i>N)printf("1\n%d",*min_element(f[N]+1,f[N+1]));
else printf("0\n%d",lower_bound(P,P+K,i)-P);
}