zoukankan      html  css  js  c++  java
  • 洛谷NOIp热身赛 T2123 数列游戏

    题目背景

    此题为改编题,特别鸣谢倪星宇同学。

    有一次,HKE和LJC在玩一个游戏。

    题目描述

    游戏的规则是这样的:LJC在纸上写下两个长度均为N的数列A和B,两个数列一一对应。HKE每次可以找两个相邻的数A[i]和A[i+1],如果它们两个不互质,HKE可以选择得到(B[i]+B[i+1])分,然后擦掉A和B位置上的第i,i+1个数,并把两个序列重新按顺序编号。当所有相邻的数互质时,游戏结束。

    HKE想知道他最大得分是多少。

    输入输出格式

    输入格式:

    第1 行一个整数N;

    第2 行N 个整数,依次表示Ai;

    第3 行N 个整数,依次表示Bi。

    输出格式:

    仅含一个整数,表示B 列被删去的可能最大和。

    输入输出样例

    输入样例#1: 复制
    6
    9 8 6 5 6 3
    11 19 12 17 18 15
    输出样例#1: 复制
    64
    //解释:擦去A[2],A[3]与A[5],A[6],得分为64

    说明

    对于30%的数据,N ≤ 20;

    对于60%的数据,N ≤ 100;

    对于80%的数据,N ≤ 500

    对于100%的数据,N ≤ 800, 1 ≤ Ai, Bi ≤ 10^9。

    题解:

      区间dp,设dp[i][j]表示i和j之间不一定要消完的最大收益,g[i][j]为i到j必须消完的收益,那么g[i][j]有两个转移,一个是枚举断点,g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]);然后我们可以消去中间的,再消i和j,g[i][j]=max(g[i][j],c[i]+c[j]+g[i+1][j-1]);

      然后是dp[i][j],如果i和k可以消,那么我们把i~k之间的都消完,然后消k+1~j。 dp[l][r]=max(dp[l][r],c[l]+c[r]+g[l+1][r-1]);如果i,j可以消,那么可以先消i,j之间的,然后消i和j。dp[l][r]=max(dp[l][r],c[l]+c[r]+g[l+1][r-1]);

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<stdio.h>
    #include<cmath>
    #define ll long long
    #define MAXN 810
    using namespace std;
    int n;
    ll a[MAXN],c[MAXN];
    ll dp[MAXN][MAXN],b[MAXN][MAXN],g[MAXN][MAXN];
    
    ll gcd(ll x,ll y){
      if(y==0) return x;
      else return gcd(y,x%y);
    }
    
    bool emt(int i,int j){
      if(gcd(a[i],a[j])!=1) return 1;
      return 0;
    }
    
    ll DP(int l,int r){
      if(l==r) return 0;
      if(b[l][r]) return dp[l][r];
      if(r==l+1) return max((ll)0,g[l][r]);
      b[l][r]=1;
      dp[l][r]=max((ll)0,DP(l+1,r));
      for(int k=l+1;k<r;k++){
        if(emt(l,k)){
          if(k==l+1) dp[l][r]=max(dp[l][r],c[l]+c[k]+DP(k+1,r));
          else dp[l][r]=max(dp[l][r],c[l]+c[k]+g[l+1][k-1]+DP(k+1,r));
        }
      }
      if(emt(l,r)) dp[l][r]=max(dp[l][r],c[l]+c[r]+g[l+1][r-1]);
      return dp[l][r];
    }
    
    int main(){
      cin>>n;
      for(int i=1;i<=n;i++) cin>>a[i];
      for(int j=1;j<=n;j++) cin>>c[j];
      memset(g,-37,sizeof(g));
      for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
          int j=i+len-1;
          if(j==i+1){
        if(emt(i,j)) g[i][j]=c[i]+c[j];
        else g[i][j]=g[0][0];
          }
          else{
        if(emt(i,j)) g[i][j]=max(g[i][j],c[i]+c[j]+g[i+1][j-1]);
        for(int k=i+1;k<j;k++) g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]);
          }
        }
      }
      printf("%lld",max(DP(1,n),(ll)0));
    }
  • 相关阅读:
    项目
    关于我
    【转载】罗胖精选|什么样的自控方法才有效?
    知识管理——得到CEO脱不花女士的一次分享
    注意由双大括号匿名类引起的serialVersionUID编译告警
    持续集成、持续交付和持续部署
    Google Cayley图数据库使用方法
    任务的属性
    团队博客地址
    个人总结
  • 原文地址:https://www.cnblogs.com/renjianshige/p/9932516.html
Copyright © 2011-2022 走看看