洛谷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));
}

 

posted @ 2018-11-08 22:35  人间失格—太宰治  阅读(256)  评论(0编辑  收藏  举报