题目:传送门
真是醉了 = =,虽然知道是区间DP,但是这题想了一天都没想出来怎么做,偷偷看了一眼题解的状态定义,又研究了一天,改了好几个小时才做出来。。太弱了。。。
状态定义:d[i][j][k]表示区间长度为i,当前位置为j,k=0时表示j是该区间的左端点,k=1时表示j是该区间的右端点,状态转移过程 k==0时,d[i][j][k]可转移到d[i+1][j-1][0]和d[i+1][i+j][1],即从当前区间的左端点向左走可得到左端点为j-1(走到当前区间左侧的点),长度为i+1的新区间,或向右走得到右端点为i+j(走到当前区间右侧的点),长度为i+1的新区间;当k==1时类似,往右走一个点,或走到当前区间左侧的第一个点。。。
一开始超时了,每个点都走了一次,后来记录了需要最早访问的点,忘了去freopen,又wa了一下 = =,改了之后a了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 10024;
int n;
int d[maxn][maxn][2];
struct P{
int x,time;
}p[maxn];
int solve(int len,int cur,int pos,int time){
if(time>p[cur].time) return d[len][cur][pos] = INF;
if(d[len][cur][pos] != -1) return d[len][cur][pos];
if(len == n) return d[len][cur][pos] = time;
int ans = INF,t1 = INF,t2 = INF;
if(!pos){
if(cur-1>=0)t1 = solve(len+1,cur-1,0,time+abs(p[cur].x-p[cur-1].x));
if(cur+len<n)t2 = solve(len+1,cur+len,1,time+abs(p[cur].x-p[cur+len].x));
} else {
if(cur+1<n)t1 = solve(len+1,cur+1,1,time+abs(p[cur].x-p[cur+1].x));
if(cur-len>=0)t2 = solve(len+1,cur-len,0,time+abs(p[cur].x-p[cur-len].x));
}
return d[len][cur][pos] = (t1<t2)?t1:t2;
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n)){
memset(d,-1,sizeof d);
int tt = INF, pp = -1;
for(int i=0;i<n;i++){
scanf("%d%d",&p[i].x,&p[i].time);
if(p[i].time<tt){
tt = p[i].time;
pp = i;
}
}
int t = INF;
t = min(t,min(solve(1,pp,1,0),solve(1,pp,0,0)));
if(t == INF) printf("No solution\n");
else printf("%d\n",t);
}
return 0;
}
太弱了太弱了太弱了啊啊啊啊啊