「NOI2013」小 Q 的修炼 解题报告

「NOI2013」小 Q 的修炼

第一次完整的做出一个提答,花了半个晚上+一个上午+半个下午

总体来说太慢了

对于此题,我认为的难点是观察数据并猜测性质和读入操作

我隔一会就思考这个sb字符串读起来怎么这么麻烦啊


首先可以发现,这个所有的选择都之后往后走,就是个topo图

  • task1,2,3

    观察到数据有形如

    s x x+11
    v 3 + c y
    v 4 + c y
    v 5 + c y
    v 6 + c y
    v 7 + c y
    v 8 + c y
    v 9 + c y
    v 10 + c y
    v 11 + c y
    v 12 + c y

    之类的东西,而且每个这样的循环后面有一个这样的东西

    i v 3 c 0 43 45
    v 1 - v 3
    i c 0 c 1 46 0
    v 1 + v 3
    v 3 - v 3
    i v 4 c 0 48 50
    v 1 - v 4
    i c 0 c 1 51 0
    v 1 + v 4
    v 4 - v 4
    ...

    发现这个就是把正的数据加到1上,负的不变并清空

    这样就没法贪心或者dp了

    然后我们又发现循环长度很小,直接爆搜就行了

    代码搞丢了..

    S_1 要讨论走哪个循环

    S_2 直接爆搜

    S_3 发现又很多组,分组爆搜

  • task4,5,6

    最开始对变量2有一个正的初值

    然后

    s 5 8
    v 2 - c 10
    v 1 + c 22750
    i c 0 c 1 8 0
    i v 2 c 9 9 10
    i c 0 c 1 14 0

    循环节长这样

    每次如果选择,会有一些跳转之类的

    发现2的初值比较小而且后面只会减

    考虑dp

    \(dp_{i,j}\)\(i\)行第\(2\)个变量的值是\(j\)的时候最大的\(1\)

    然后模拟转移,记录路径就可以了

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using std::max;
    const int N=6010;
    int n,m;
    char op[5],t0[10],t1[10];
    int x0,x1,x2,x2;
    struct koito_yuu
    {
      int op,a,b,c;
      koito_yuu(){}
      koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;}
    }yuu[N];
    struct node
    {
      int i,j,cho;
      node(){}
      node(int I,int J,int Cho){i=I,j=J,cho=Cho;}
    }pre[N][5010];
    ll dp[N][5010];
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
      {
          scanf("%s",op);
          if(op[0]=='s')
          {
              tim[++k]=i;
              scanf("%d%d",&x1,&x2);
              yuu[i]=koito_yuu(1,x1,x2,0);
          }
          else if(op[0]=='v')
          {
              scanf("%d%s%s%d",&x0,t0,t1,&x1);
              yuu[i]=koito_yuu(2,x0,t1[0]=='+'?x1:-x1,0);
          }
          else 
          {
              scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);
              if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(3,x2,0,0);
              else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(4,x1,x2,x3);
          }
      }
      memset(dp,-0x3f,sizeof dp);
      int inf=dp[0][0];
      dp[0][0]=0;
      for(int i=1;i<=n;i++)
          for(int j=0;j<=5000;j++)
              if(dp[i-1][j]!=inf)
              {
                  if(yuu[i].op==1)
                  {
                      int a=yuu[i].a,b=yuu[i].b;
                      if(dp[a][j]<dp[i][j])
                      {
                          pre[a][j]=node(i,j,1);
                          dp[a][j]=dp[i][j];
                      }
                      if(dp[b][j]<dp[i][j])
                      {
                          pre[b][j]=node(i,j,2);
                          dp[b][j]=dp[i][j];
                      }
                  }
                  else if(yuu[i].op==2)
                  {
                      int a=yuu[i].a,b=yuu[i].b;
                      if(a==1)
                      {
                          if(dp[i+1][j]<dp[i][j]+b)
                          {
                              pre[i+1][j]=node(i,j,0);
                              dp[i+1][j]=dp[i][j]+b;
                          }
                      }
                      else
                      {
                          int t=max(0,j+b);
                          if(dp[i+1][t]<dp[i][j])
                          {
                              pre[i+1][t]=node(i,j,0);
                              dp[i+1][t]=dp[i][j];
                          }
                      }
                  }
                  else if(yuu[i].op==3)
                  {
                      int a=yuu[i].a;
                      if(dp[a][j]<dp[i][j])
                      {
                          pre[a][j]=node(i,j,0);
                          dp[a][j]=dp[i][j];
                      }
                  }
                  else
                  {
                      int a=yuu[i].a,b=yuu[i].b,c=yuu[i].c;
                      if(j<a)
                      {
                          if(dp[b][j]<dp[i][j])
                          {
                              pre[b][j]=node(i,j,0);
                              dp[b][j]=dp[i][j];
                          }
                      }
                      else
                      {
                          if(dp[c][j]<dp[i][j])
                          {
                              pre[c][j]=node(i,j,0);
                              dp[c][j]=dp[i][j];
                          }
                      }
                  }
              }
      int tj=0;
      for(int i=1;i<=5000;i++)
          if(dp[n+1][tj]<dp[n+1][i])
              tj=i;
      int ti=n+1,cnt=0;
      while(ti)
      {
          int tx=ti,ty=tj;
          ti=pre[tx][ty].i,tj=pre[tx][ty].j;
          if(pre[tx][ty].cho) ans[++cnt]=pre[tx][ty].cho;
      }
      for(int i=cnt;i;i--) printf("%d\n",ans[i]);
      return 0;
    }

    4,5,6都是一样的

    我本地跑6的时候居然开不下空间,还压了一会T_T

  • task7,8,9,10

    这四个点就是前面的结合

    最开始的时候有2控制跳转的东西

    中间就是1,2,3点的循环

    差不多175行一个周期

    对周期压变量2的长度dp,每个周期里面爆搜

    说起来简单,写起来还是很麻烦的

    我这个代码要把in的最后几行删掉

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using std::max;
    using std::min;
    const int N=35010;
    int n,m;
    char op[5],t0[10],t1[10];
    int x0,x1,x2,x3;
    struct koito_yuu
    {
      int op,a,b,c;
      koito_yuu(){}
      koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;}
    }yuu[N];
    struct node
    {
      int i,j,cho;
      node(){}
      node(int I,int J,int Cho){i=I,j=J,cho=Cho;}
    }pre[N][1010];
    ll dp[N][1010];
    int Id[N],as[N][20],yuy[20][20],ct[N];
    ll solve(int id,int L,int R)
    {
      int n=0;
      for(int i=L;i<=R;i++)
      {
          if(yuu[i].op==1) ++n,yuy[n][0]=0;
          if(yuu[i].op==2) yuy[n][++yuy[n][0]]=yuu[i].b;
          if(yuu[i].op==3) break;
      }
      ll mx=-(1ll<<52);
      ct[id]=n;
      for(int s=0;s<1<<n;s++)
      {
          ll sum[20]={};
          for(int i=1;i<=n;i++)
              if(s>>i-1&1)
              {
                  for(int j=1;j<=10;j++)
                      sum[j]+=yuy[i][j];
              }
          ll su=0;
          for(int i=1;i<=10;i++) su+=sum[i]>0?sum[i]:-sum[i];
          if(mx<su)
          {
              mx=su;
              for(int i=1;i<=n;i++)
                  if(s>>i-1&1)
                      as[id][i]=1;
                  else
                      as[id][i]=2;
          }
      }
      return mx;
    }
    int endro[N],k,ans[N];
    int main()
    {
        freopen("train8.in","r",stdin);
        freopen("train8.out","w",stdout);
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
      {
          scanf("%s",op);
          if(op[0]=='s')
          {
              scanf("%d%d",&x1,&x2);
              x2=min(x2,n+1);
              yuu[i]=koito_yuu(1,x1,x2,0);
          }
          else if(op[0]=='v')
          {
              scanf("%d%s%s%d",&x0,t0,t1,&x1);
              if(t1[0]=='c')
              {
                  yuu[i]=koito_yuu(2,x0,t0[0]=='+'?x1:-x1,0);
              }
              else
              {
                  yuu[i]=koito_yuu(3,x0,0,x1);
                  if(x0==12) endro[++k]=i;
              }
          }
          else
          {
              scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);
              x2=min(x2,n+1),x3=min(x3,n+1);
              if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(4,x2,0,0);
              else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(5,x1,x2,x3);
          }
      }
      memset(dp,-0x3f,sizeof dp);
      dp[1][0]=0;
      for(int i=1;i<=k;i++)
      {
          int tp;
          for(int j=endro[i-1]+1;;j++)
                if(yuu[j].op==1&&yuu[j].b-yuu[j].a==11)
                {
                    tp=j-1;
                    break;
                }
          ll ad=solve(i,tp+1,endro[i]);
          for(int l=endro[i-1]+1;l<=tp;l++)
              for(int j=0;j<=1000;j++)
              {
                  if(yuu[l].op==1)
                  {
                      int a=yuu[l].a,b=yuu[l].b;
                      if(dp[a][j]<dp[l][j])
                      {
                          dp[a][j]=dp[l][j];
                          pre[a][j]=node(l,j,1);
                      }
                      if(dp[b][j]<dp[l][j])
                      {
                          dp[b][j]=dp[l][j];
                          pre[b][j]=node(l,j,2);
                      }
                  }
                  else if(yuu[l].op==2)
                  {
                      int b=yuu[l].b;
                      int t=max(0,j+b);
                      if(dp[l+1][t]<dp[l][j])
                      {
                          dp[l+1][t]=dp[l][j];
                          pre[l+1][t]=node(l,j,0);
                      }
                  }
                  else if(yuu[l].op==4)
                  {
                      int a=yuu[l].a;
                      if(dp[a][j]<dp[l][j])
                      {
                          dp[a][j]=dp[l][j];
                          pre[a][j]=node(l,j,0);
                      }
                  }
                  else
                  {
                      int a=yuu[l].a,b=yuu[l].b,c=yuu[l].c;
                      if(j<a)
                      {
                          if(dp[b][j]<dp[l][j])
                          {
                              dp[b][j]=dp[l][j];
                              pre[b][j]=node(l,j,0);
                          }
                      }
                      else
                      {
                          if(dp[c][j]<dp[l][j])
                          {
                              dp[c][j]=dp[l][j];
                              pre[c][j]=node(l,j,0);
                          }
                      }
                  }
              }
          int s=tp+1,t=endro[i]+1;
          Id[s]=i;
          for(int j=0;j<=1000;j++)
              if(dp[t][j]<dp[s][j]+ad)
              {
                  dp[t][j]=dp[s][j]+ad;
                  pre[t][j]=node(s,j,3);
              }
      }
      //9.22925584
      //10.20218188
      int tj=0;
      for(int i=1;i<=1000;i++)
          if(dp[n+1][tj]<dp[n+1][i])
              tj=i;
      int ti=n+1,cnt=0;
      while(ti)
      {
          int tx=ti,ty=tj;
          ti=pre[tx][ty].i,tj=pre[tx][ty].j;
          if(pre[tx][ty].cho)
          {
              if(pre[tx][ty].cho==3)
              {
                  int id=Id[ti];
                  for(int i=ct[id];i;i--) ans[++cnt]=as[id][i];
              }
              else
                  ans[++cnt]=pre[tx][ty].cho;
          }
      }
      for(int i=cnt;i;i--) printf("%d\n",ans[i]);
        return 0;
    }

2019.4.12

转载于:https://www.cnblogs.com/butterflydew/p/10696999.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值