测试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
*/
View Code

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);
}
View Code

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;
}
View Code

DP复杂度是稳定的。

搜索这里虽然快,但是可以被卡,不稳定。(我赛后被北岸大神的点卡了)

但是考场上想错了。想的Tm^3 DP。实际上Tm^2就可以。以为一次扩展一大截,实际上一次扩展一个就好。

虽然有很多时间点是没用的,但冗余还是比搜索少,至少不会被卡。

以后要尽量想这种复杂度确定的。

(虽然很多人搜索A了)

观察一开始想的,一次扩展一大节的,其实有很多是冗余的。例如:从i->i+1->i+2->i+3 和 i->i+3是等效的。

似乎可以用搜索的思路每次只扩展相反的方向。感觉复杂度可能是一样的,在前后缀优化计算成O(1)后。

只是常数可能会大。

两种,一个是以反向返回为阶段划分,一个是以边界拓展一个为状态划分。

只是没必要用第一种,复杂度应该是一样的,再用前缀和很麻烦,而且不能优化。

第二种要打递推。递归式DP麻烦。而且想递归的话难想到这个转移。

去想他运动的方式。

posted @ 2019-08-12 14:34  seamtn  阅读(178)  评论(0编辑  收藏  举报