测试18:T2:可爱精灵宝贝
我的考场剪枝搜索:500+ms
一次扩展一段,只反向扩展,二维前后缀O(1)转移
#include<bits/stdc++.h> #define F(i,a,b) for(rg int i=a;i<=b;++i) #define rg register #define il inline #define LL long long #define pf(a) printf("%d ",a) #define phn puts("") using namespace std; int read(); /* 删除调试语句。 */ //T pos dis int n,org,m,bigt; //int a[110],b[118],t[158]; il int max(const int x ,const int y){return x>y?x:y;} int pre[4005][110],bac[4005][118]; struct node{ int a,b,t; friend bool operator < (node x,node y){ return x.a<y.a; } }s[118]; int ans; void dfs(int t,int pos,int las,int val){ ans=max(ans,val); // pf(t);phn;++tot; int fir,sum,tome; if(pos<=las){ for(int i=las+1;i<=m;++i){ fir=t-(s[pos].a-1)+2000; sum=pre[fir][i]-pre[fir][las]; if(!sum)continue; /* if(sum<0){ puts("88");while(1); }*/ tome=t+s[i].a-s[pos].a; if(tome>bigt)break; dfs(tome,i,pos,val+sum); } } if(pos>=las){ for(int i=las-1;i>=1;--i){ fir=t-(n-s[pos].a)+2000; sum=bac[fir][i]-bac[fir][las]; if(!sum)continue; /* if(sum<0){ puts("88");while(1); }*/ tome=t+s[pos].a-s[i].a; if(tome>bigt)break; dfs(tome,i,pos,val+sum); } } } int main(){ n=read();org=read();m=read(); s[m+1].a=org;s[m+1].b=0;s[m+1].t=0; F(i,1,m){ s[i].a=read();s[i].b=read();s[i].t=read();bigt=max(bigt,s[i].t); } ++m; sort(s+1,s+m+1); int p=0; F(i,1,m){ if(s[i].a==org){ p=i;break; } } F(i,1,4001){ F(j,1,m){ pre[i][j]=pre[i][j-1]+(s[j].a-1+i>s[j].t+2000?0:s[j].b); } for(rg int j=m;j>=1;--j){ bac[i][j]=bac[i][j+1]+(n-s[j].a+i>s[j].t+2000?0:s[j].b); } } dfs(1,p,p,0); printf("%d\n",ans); // pf(tot);phn; } il int read(){ int s=0;char ch; while(ch=getchar(),!isdigit(ch)); for(;isdigit(ch);s=s*10+(ch^48),ch=getchar()); return s; } /* g++ 2.cpp -g ./a.out 10 5 4 1 30 5 3 5 7 7 10 11 9 100 23 100 5 20 1 30 5 3 5 7 7 10 12 9 100 23 10 30 5 30 5 7 70 10 12 90 100 23 11 30 5 31 5 70 71 10 102 91 100 23 12 30 5 32 5 1500 72 10 1200 92 100 2000 51 30 1500 53 5 7 57 10 12 59 100 1500 */
wxy 搜索:32ms
一次只扩展一个。(clock会慢,无用)
#include<bits/stdc++.h> #define ll long long #define cri const register int #define re register #define ll long long using namespace std; int ma=0,n,k,m,ans=0,sum=0,can[5000]; struct node{ int a,b,t; friend bool operator <(const node A,const node B){ if(A.a==B.a) return A.b<B.b; return A.a<B.a; } }p[1100]; void dfs(cri sta,int l,int r,cri tim,int sor,int lst){ while(r<=m&&p[r].a==sta){ lst-=p[r].b; if(p[r].t>=tim) sor+=p[r].b; r++; } while(l&&p[l].a==sta){ lst-=p[l].b; if(p[l].t>=tim) sor+=p[l].b; l--; } // if(clock()>995000){ // printf("%d\n",ans); // exit(0); // } // if(lst+sor<=ans||sor+can[ma]-can[tim]<=ans) return; while(l&&p[l].t<sta-p[l].a+tim) lst-=p[l].b,l--; while(r<=m&&p[r].t<p[r].a-sta+tim) lst-=p[r].b,r++; // if(sor+lst<=ans) return; if(!l&&r>m) { ans=max(ans,sor); return; } if(r<=m) dfs(p[r].a,l,r,tim+p[r].a-sta,sor,lst); if(l) dfs (p[l].a,l,r,tim+sta-p[l].a,sor,lst); } int main(){ scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].t); if(abs(p[i].a-k)+1>p[i].t) --i,--m; else sum+=p[i].b,can[p[i].t]+=p[i].b,ma=max(p[i].t,ma); } for(int i=1;i<=ma;i++) can[i]+=can[i-1]; sort(p+1,p+m+1); int l=lower_bound(p+1,p+m+1,node{k,-1,0})-p; dfs(k,l-1,l,1,0,sum); printf("%d\n",ans); }
milkfeng Dp(比大脸的1800+快多了):500+
Tm^2。一次扩展一个
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define Maxn 2050 #define Reg register #define INF 0x7fffff #define _max(x,y) ((x)>(y)?(x):(y)) #define _abs(x) ((x)<0?(-1*(x)):(x)) using namespace std; int n,k,m,mxx,ans,tot,mid,dp[Maxn][150][150][2]; struct Node {int a,b,t;} Q[Maxn]; bool comp(Node a,Node b) {return a.a<b.a;} int main() { scanf("%d%d%d",&n,&k,&m); Q[++tot].a=k,Q[tot].b=0,Q[tot].t=0; for(Reg int i=1,a,b,t;i<=m;++i) { scanf("%d%d%d",&a,&b,&t); if(a==k) Q[1].b+=b; else { Q[++tot].a=a,Q[tot].b=b,Q[tot].t=t; mxx=_max(mxx,Q[tot].t); } } sort(Q+1,Q+tot+1,comp); for(Reg int i=1;i<=tot;++i) if(Q[i].a==k) mid=i; for(Reg int i=1;i<=mxx;++i) for(Reg int j=mid;j>=1;--j) for(Reg int p=mid,sum;p<=tot;++p) dp[i][j][p][0]=dp[i][j][p][1]=-INF; dp[1][mid][mid][0]=dp[1][mid][mid][1]=Q[mid].b; for(Reg int i=1;i<=mxx;++i) { for(Reg int j=mid;j>=1;--j) { for(Reg int p=mid,sum;p<=tot;++p) { if(p+1<=tot&&i+Q[p+1].a-Q[j].a<=mxx) { sum=dp[i][j][p][0]; if(Q[p+1].t>=i+Q[p+1].a-Q[j].a) sum+=Q[p+1].b; dp[i+Q[p+1].a-Q[j].a][j][p+1][1]=_max(dp[i+Q[p+1].a-Q[j].a][j][p+1][1],sum); } if(j-1>=1&&i+Q[j].a-Q[j-1].a<=mxx) { sum=dp[i][j][p][0]; if(Q[j-1].t>=i+Q[j].a-Q[j-1].a) sum+=Q[j-1].b; dp[i+Q[j].a-Q[j-1].a][j-1][p][0]=_max(dp[i+Q[j].a-Q[j-1].a][j-1][p][0],sum); } if(j-1>=1&&i+Q[p].a-Q[j-1].a<=mxx) { sum=dp[i][j][p][1]; if(Q[j-1].t>=i+Q[p].a-Q[j-1].a) sum+=Q[j-1].b; dp[i+Q[p].a-Q[j-1].a][j-1][p][0]=_max(dp[i+Q[p].a-Q[j-1].a][j-1][p][0],sum); } if(p+1<=tot&&i+Q[p+1].a-Q[p].a<=mxx) { sum=dp[i][j][p][1]; if(Q[p+1].t>=i+Q[p+1].a-Q[p].a) sum+=Q[p+1].b; dp[i+Q[p+1].a-Q[p].a][j][p+1][1]=_max(dp[i+Q[p+1].a-Q[p].a][j][p+1][1],sum); } ans=_max(ans,_max(dp[i][j][p][0],dp[i][j][p][1])); } } } printf("%d",ans); return 0; }
DP复杂度是稳定的。
搜索这里虽然快,但是可以被卡,不稳定。(我赛后被北岸大神的点卡了)
但是考场上想错了。想的Tm^3 DP。实际上Tm^2就可以。以为一次扩展一大截,实际上一次扩展一个就好。
虽然有很多时间点是没用的,但冗余还是比搜索少,至少不会被卡。
以后要尽量想这种复杂度确定的。
(虽然很多人搜索A了)
观察一开始想的,一次扩展一大节的,其实有很多是冗余的。例如:从i->i+1->i+2->i+3 和 i->i+3是等效的。
似乎可以用搜索的思路每次只扩展相反的方向。感觉复杂度可能是一样的,在前后缀优化计算成O(1)后。
只是常数可能会大。
两种,一个是以反向返回为阶段划分,一个是以边界拓展一个为状态划分。
只是没必要用第一种,复杂度应该是一样的,再用前缀和很麻烦,而且不能优化。
第二种要打递推。递归式DP麻烦。而且想递归的话难想到这个转移。
去想他运动的方式。
Informatik verbindet dich und mich.
信息将你我连结。