HDU 5900 QSC and Master(区间DP)

本文介绍了一种利用区间动态规划解决特定数对取分问题的方法,通过判断数对间的最大公约数来确定能否合并数对以获得最大得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出nn个数对(keyi,vali),对于相邻的两个数对,如果它们的键值不互素则可以同时拿走这两个数对,得分为其价值之和,问最多可以得多少分

Input

第一行一整数TT表示用例组数,每组用例首先输入一整数n表示数对的个数,之后输入nn个整数keyi表示每个数对的键值,最后输入nn个整数vali表示每个数对的价值

(1T10,1n300,1keyi109,0vali109)(1≤T≤10,1≤n≤300,1≤keyi≤109,0≤vali≤109)

Output

输出最大得分

Sample Input

3
3
1 2 3
1 1 1
3
1 2 4
1 1 1
4
1 3 4 3
1 1 1 1

Sample Output

0
2
0

Solution

区间DPDP,以dp[l][r]dp[l][r]表示从第ll个数对到第r个数对可以拿到的最大得分,有两种方案,要么把该区间分成两部分分别考虑,要么就是第l+1l+1个数对到第r1r−1个数对全部被拿走且gcd(keyl,keyr)>1gcd(keyl,keyr)>1,这样第ll个数对和第r个数对可以凑一起拿走,为快速判断是否可以将区间[l+1,r1][l+1,r−1]的数对全部拿走,对价值求前缀和sumi=j=1ivaljsumi=∑j=1ivalj,如果dp[l+1][r1]=sumr1sumldp[l+1][r−1]=sumr−1−suml则说明区间[l+1,r1][l+1,r−1]可以全部被拿走,以此求出dp[1][n]dp[1][n]即为答案,时间复杂度O(Tn3)O(Tn3)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 333
int T,n,a[maxn],v[maxn];
ll sum[maxn],dp[maxn][maxn];
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
ll dfs(int l,int r)
{
    if(dp[l][r]!=-1)return dp[l][r];
    ll ans=-1;
    if(l==r)ans=0;
    else if(r==l+1)
    {
        if(gcd(a[l],a[r])>1)ans=v[l]+v[r];
        else ans=0;
    }
    else 
    {
        int temp=gcd(a[l],a[r]);
        if(temp!=1&&dfs(l+1,r-1)==sum[r-1]-sum[l])ans=sum[r]-sum[l-1];
        for(int i=l;i<r;i++)ans=max(ans,dfs(l,i)+dfs(i+1,r));
    }
    return dp[l][r]=ans;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(dp,-1,sizeof(dp));
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]),sum[i]=sum[i-1]+v[i];
        printf("%I64d\n",dfs(1,n));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值