• bzoj4760[USACO2017 Jan]Hoof,Paper,Scissors


    题意:玩n次剪刀石头布,对方每次出什么已经知道了.你出的招数必须是连续的几段(不能超过k+1段),问你最多赢几次.(n<=100000,k<=20)

    正常做法:f[i][j][k]表示前i次,分j段,最后一次出的是k(k=0,1,2)时最多赢几次,可以O(nk)解决,转移时看最近一次有没有新分一段即可.

    智障做法:我们同样定义f[i][j][k]表示前i次,分j段,最后一次出的是k时最多赢几次,但转移的时候考虑最近的一段,也就是枚举最近的一段是从哪里开始的,那么这就变成了1D1D动态规划,打表观察到决策单调性,可以大力写一个决策单调性O(nlognk)解决,强行多一个log也可以过

    讲道理决策单调性还是很好写的

     

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    int sum[3][maxn];
    int f[22][maxn][3];
    void solve(int l,int r,int L,int R,int j,int t){//printf("%d %d %d %d %d
    ",l,r,L,R,j);
      if(l>r)return;
      int mid=(l+r)>>1,g=0,tmp=0;
      for(int i=L;i<=R&&i<=mid;++i){
        tmp=sum[t][mid]-sum[t][i];
        for(int k=0;k<3;++k)
          if(tmp+f[j-1][i][k]>f[j][mid][t]){
        f[j][mid][t]=f[j-1][i][k]+tmp;g=i;
          }
      }
      solve(l,mid-1,L,g,j,t);solve(mid+1,r,g,R,j,t);
    }
    int main(){
      int n,k;
      scanf("%d%d",&n,&k);k++;
      char buf[3];
      for(int i=1;i<=n;++i){
        scanf("%s",buf);
        for(int k=0;k<3;++k)sum[k][i]=sum[k][i-1];
        if(buf[0]=='H')sum[0][i]++;
        else if(buf[0]=='S')sum[1][i]++;
        else sum[2][i]++;
      }
      for(int j=1;j<=k;++j){
        for(int t=0;t<3;++t)solve(1,n,0,n-1,j,t);
      }//printf("%d
    ",f[1][4]);
      int ans=0;
      for(int i=1;i<=k;++i)for(int t=0;t<3;++t)ans=max(ans,f[i][n][t]);
      printf("%d
    ",ans);
      return 0;
    }

     

     

  • 相关阅读:
    project 2013 激活 key 7YHNW-RVCQY-VBDB2-QX69Q-B96WK viso 66DNF-28W69-W4PPV-W3VYT-TJDBQ
    电脑快捷键
    Error (167005): Can't assign I/O pad "GX_TX" to PIN_AG27 because this causes failure in the placement of the other atoms in its associated channel
    学习资源
    数值孔径
    网络通信芯片
    DMD数字微镜
    运放输入阻抗
    DS18B20测温
    LED灯开关电路
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6397295.html
Copyright © 2020-2023  润新知