• BZOJ3877 : [Ahoi2014&Jsoi2014]保龄球


    考虑从前往后放所有轮。

    如果上一轮是全中:

    那么这一轮如果是补中,一定放第一次最小的,这样可以让第一次大的放在其它补中之后。

    如果这一轮是失误,那么一定放总分最大的。

    如果上一轮是补中:

    这一轮一定放第一次最大的。

    所以每次要么放补中里第一次最小的,要么放补中里第一次最大的。

    最优解中一定是全中补中先交替放,直到一方不足,然后按照剩下那一放对失误轮进行贪心。

    因为最后第二轮的限制,最后一轮可能是个特例,因此枚举哪轮失误是特例,再枚举失误轮贪心策略是按照总分还是第一次从大到小取,然后DP求最优解。

    将补中按照第一次得分排序,设$f[i][l][r][j][k][o]$表示已经放了$i$个全中,还没放的补中是区间$[l,r]$,已经放了前$j$个非特例失误轮,特例有没有放为$k$,目前最后放的那轮是全中/补中/失误时的最优解。

    时间复杂度$O(n^5)$,常数很小。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=53;
    int n,flag,i,j,_,ca,cb,cc,cd,ans,f[N][N][N][N][2][3];
    struct P{int x,y,z;}a[N],b[N],c[N],d,_c[N];
    inline bool cmpx(const P&a,const P&b){return a.x>b.x;}
    inline bool cmpz(const P&a,const P&b){return a.z>b.z;}
    inline void up(int&a,int b){a<b?(a=b):0;}
    void solve(){
      int i,j,r,k,S,o,w,v,t,x,y,cana,cane;
      for(i=0;i<=ca;i++)for(j=0;j<=cb;j++)for(r=cb;r>=j;r--)for(k=0;k<=cc;k++)for(S=0;S<=cd;S++)for(o=0;o<3;o++)f[i][j][r][k][S][o]=-1;
      f[0][0][cb][0][0][0]=0;
      for(i=0;i<=ca;i++)for(j=0;j<=cb;j++)for(r=cb;r>=j;r--)for(k=0;k<=cc;k++)for(S=0;S<=cd;S++)for(o=0;o<3;o++){
        w=f[i][j][r][k][S][o];
        if(w<0)continue;
        cana=cane=1;
        if(i+j+cb-r+k+S+1==n-1)cana=flag,cane=flag^1;
        if(cana&&i<ca){
          t=10;
          if(o)t<<=1;
          up(f[i+1][j][r][k][S][1],w+t);
        }
        if(!cane)continue;
        if(j<r){
          x=b[j+1].x,y=b[j+1].y;
          t=x+y;
          if(o==1)t=(x+y)<<1;
          if(o==2)t=(x<<1)+y;
          up(f[i][j+1][r][k][S][2],w+t);
          x=b[r].x,y=b[r].y;
          t=x+y;
          if(o==1)t=(x+y)<<1;
          if(o==2)t=(x<<1)+y;
          up(f[i][j][r-1][k][S][2],w+t);
        }
        if(k<cc){
          x=c[k+1].x,y=c[k+1].y;
          t=x+y;
          if(o==1)t=(x+y)<<1;
          if(o==2)t=(x<<1)+y;
          up(f[i][j][r][k+1][S][0],w+t);
        }
        if(S<cd){
          x=d.x,y=d.y;
          t=x+y;
          if(o==1)t=(x+y)<<1;
          if(o==2)t=(x<<1)+y;
          up(f[i][j][r][k][1][0],w+t);
        }
      }
      for(j=0;j<=cb;j++)for(o=0;o<3;o++)up(ans,f[ca][j][j][cc][cd][o]);
    }
    void cal(){
      sort(c+1,c+cc+1,cmpz);
      solve();
      sort(c+1,c+cc+1,cmpx);
      solve();
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++){
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].z=a[i].x+a[i].y;
      }
      if(a[n].x==10){
        n++;
        flag=1;
        scanf("%d%d",&a[n].x,&a[n].y);
        a[n].z=a[n].x+a[n].y;
      }
      for(i=1;i<=n;i++){
        if(a[i].x==10){ca++;continue;}
        if(a[i].z==10){b[++cb]=a[i];continue;}
        c[++cc]=a[i];
      }
      sort(b+1,b+cb+1,cmpx);
      cal();
      for(i=1;i<=cc;i++){
        cd=1,d=c[i];
        for(j=1;j<=cc;j++)_c[j]=c[j];
        for(_=0,j=1;j<=cc;j++)if(j!=i)c[++_]=c[j];
        cc=_;
        cal();
        for(cc++,j=1;j<=cc;j++)c[j]=_c[j];
      }
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    (周日赛) Average is not Fast Enough!
    过山车
    (寒假CF3)B
    (寒假CF3)坑坑坑
    (周六赛1)Sum it up
    畅通工程
    vue 动态添加form表单item 校验问题
    html2canvas转pdf分页隔断问题处理
    vue中html转pdf并下载功能
    一个简单的滑动溢出效果
  • 原文地址:https://www.cnblogs.com/clrs97/p/8531832.html
Copyright © 2020-2023  润新知