Daimayuan Online Judge 快快变大

2 篇文章 0 订阅

给定一个长度为 nn 的数组 a1,a2,…,ana1,a2,…,an,接下来进行 n−1n−1 次操作。每次选择一个下标 xx ,将 axax 和 ax+1ax+1 合并成 ax×ax+1mod1000003ax×ax+1mod1000003 ,并且你会获得 (ax−ax+1)2(ax−ax+1)2 的分数。

所以每次操作后,数组的长度将会减 11,当最后只剩下一个元素时停止操作。输出最终能获得的最大分数。

输入格式

第一行一个数字 nn。

接下来一行 nn 个整数 a1,a2,…,ana1,a2,…,an。

输出格式

一个数,表示答案。

样例输入

3
1 2 3

样例输出

26

数据规模

所有数据保证 1≤n≤300,1≤ai≤1061≤n≤300,1≤ai≤106。

思路:这个题是区间dp,这个题其实是基于分治思想,分治主要是将连续的数组进行分解,是通过枚举分界点来实现的。区间的大小是任意的,区间被分割也是任意的。第一层循环是控制数组的长度,第二层循环是控制起点但i只能到 i+len-1<=n,(第三层循环控制分界点位置)。当题目要求求出任意的连续的子串,而且操作的可能是相邻两个,也可能是多个。一般分治还会用到前缀和,这相当于优化吧。与这题十分相似的是石子合并,都是用分治来写的。分治的写法是从k分开,f[i][k] + f[k+1][j] 。

完整代码:

#include <bits/stdc++.h>
#include <cstring>
using namespace std;

#define int long long
const int mod=1000003;

const int N=400;
int a[N],sum[N][N];
int f[N][N];

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }

    for(int i=1;i<=n;i++)
    {
        sum[i][i]=1;
        sum[i][i-1]=1;
        for(int j=i;j<=n;j++)
        {
            sum[i][j]=(sum[i][j-1]*a[j])%mod;
        }
    }

    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            for(int k=i;k<j;k++)
            {
                f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+(sum[i][k]-sum[k+1][j])*(sum[i][k]-sum[k+1][j]));
            }
        }
    }
    cout<<f[1][n]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值