洛谷-5154 数列游戏

题目描述
游戏的规则是这样的: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

说明/提示
对于100%的数据,N ≤ 800, 1 ≤ Ai, Bi ≤ 10^9。

解释:首先如果 i i i j j j相互消除,那么 [ i + 1 , j − 1 ] [i+1,j-1] [i+1,j1]必然消除,所以我们预处理出来可以被消除的区间dp
d p [ i ] [ j ] = ( g c d ( a [ i ] , a [ j ] ) ! = 1 )   a n d   d p [ i + 1 ] [ j − 1 ] dp[i][j]=(gcd(a[i],a[j])!=1) \ and \ dp[i+1][j-1] dp[i][j]=(gcd(a[i],a[j])!=1) and dp[i+1][j1]
d p [ i ] [ j ] = d p [ i ] [ k ]   a n d   d p [ k + 1 ] [ j ] dp[i][j]=dp[i][k] \ and \ dp[k+1][j] dp[i][j]=dp[i][k] and dp[k+1][j]
处理出来后,可以看成一个区间选择问题,选择权最大
继续dp
d p [ i ] = m a x ( d p [ i − 1 ] , d p [ s [ j ] . l − 1 ] + s [ j ] . v )     , i = = s [ j ] . r dp[i]=max(dp[i-1],dp[s[j].l-1]+s[j].v)\ \ \ ,i==s[j].r dp[i]=max(dp[i1],dp[s[j].l1]+s[j].v)   ,i==s[j].r其他情况下
d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i1]

其中s数组存线段,l,r分别左右端点,v为权值,完成

#include<iostream>
#include<algorithm>
#define N 803
using namespace std;
//int N =803;
long long A[N]={0},B[N]={0};
int n=0;
bool vis[N][N]={0};
long long dp[1000]={0}; 
long long gcd(long long a,long long b){
    if(b==0) return a;
    return gcd(b,a%b);
}
struct node{
    int l,r;
    long long v;
};
node s[N*N];
bool cmp(const node &x,const node &y){
    return x.r<y.r;
}
int t=0;
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>A[i];
    for(int i=1;i<=n;i++) cin>>B[i],B[i]+=B[i-1];
    for(int i=1;i<n;i++) vis[i][i+1]=(gcd(A[i],A[i+1])!=1);
    for(int len=4;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int k=i+len-1;
            vis[i][k]|=vis[i+1][k-1]&&(gcd(A[i],A[k])!=1);
            for(int j=i+1;j+1<k;j++){
                vis[i][k]|=vis[i][j]&&vis[j+1][k];
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            if(vis[i][j]){
                ++t;
                s[t].l=i,s[t].r=j;s[t].v=B[j]-B[i-1];
            }
        }
    }
   sort(s+1,s+1+t,cmp);
	for(int i=1,j=1;i<=n;i++){
		dp[i]=max(dp[i],dp[i-1]);
		if(j<=t&&i==s[j].r) dp[i]=max(dp[i],dp[s[j].l-1]+s[j].v),j++,i--;
	}
	cout<<dp[n]<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值