SCUT - 299 - Kaildls的数组划分 - dp - 高精

https://scut.online/p/299
\(dp[i][k]\) 为前 \(i\) 个数分 \(k\) 组的最大值,那么 $dp[i][k]=max_{p=1}^{i-1}{dp[p][k-1]*sum(p+1,i)} $

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

struct BigInt {
    const static int mod = 10000;
    const static int DLEN = 4;
    vector<int> a;
    int len;

    BigInt() {
        a.resize(1);
        len = 1;
    }

    BigInt(int v) {
        a.resize(2);
        len = 0;
        do {
            a[len++] = v%mod;
            v /= mod;
        } while(v);
    }

    BigInt operator +(const BigInt &b)const {
        BigInt res;
        res.len = max(len,b.len);
        res.a.resize(res.len+1);
        for(int i = 0; i <= res.len; i++)
            res.a[i] = 0;
        for(int i = 0; i < res.len; i++) {
            res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);
            res.a[i+1] += res.a[i]/mod;
            res.a[i] %= mod;

        }
        if(res.a[res.len] > 0)
            res.len++;
        return res;
    }

    BigInt operator *(const BigInt &b)const {
        BigInt res;
        res.a.resize(len + b.len);
        for(int i = 0; i < len; i++) {
            int up = 0;
            for(int j = 0; j < b.len; j++) {
                int temp = a[i]*b.a[j] + res.a[i+j] + up;
                res.a[i+j] = temp%mod;
                up = temp/mod;

            }
            if(up != 0)
                res.a[i + b.len] = up;

        }
        res.len = len + b.len;
        while(res.a[res.len - 1] == 0 &&res.len > 1)
            res.len--;
        res.a.resize(res.len);
        return res;
    }

    bool operator >(const BigInt &b)const {
        if(len>b.len)
            return true;
        else if(len==b.len) {
            int ln=len-1;
            while(a[ln]==b.a[ln]&&ln>=0)
                ln--;
            if(ln>=0&&a[ln]>b.a[ln])
                return true;
            else
                return false;
        } else
            return false;
    }

    void output() {
        printf("%d",a[len-1]);
        for(int i = len-2; i >=0 ; i--)
            printf("%04d",a[i]);
        printf("\n");
    }
};

int a[205];
BigInt dp[205][205];
//区间[i,j]分为k段取得的最大值

inline int suma(int i,int j) {
    return a[j]-a[i-1];
}

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
    }
    for(int i=1; i<=n; i++) {
        a[i]+=a[i-1];
    }

    for(int i=1; i<=n; i++)
        dp[i][1]=BigInt(suma(1,i));

    for(int i=2; i<=n; i++) {
        int c=min(i,k);
        for(int ki=2; ki<=c; ki++) {
            for(int p=1; p<=i-1; p++) {
                BigInt t=dp[p][ki-1]*BigInt(suma(p+1,i));
                if(t>dp[i][ki])
                    dp[i][ki]=t;
            }
        }
    }

    dp[n][k].output();
}

原文地址:https://www.cnblogs.com/Yinku/p/11026073.html

时间: 2024-10-13 05:42:00

SCUT - 299 - Kaildls的数组划分 - dp - 高精的相关文章

【日常学习】【区间DP+高精】codevs1166 矩阵取数游戏题解

题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小. 先上题目 题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. 每次取走的各个元素只能是该元素所在行的行首或行尾: 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素

[DP][高精][NOIP]Hanoi双塔问题

题目梗概 Hanoi塔问题的基础上,每种圆盘加了一个.实际内容并没有变化. 思考 首先来一波Hanoi问题的步数公式推导: 首先n个不同的圆盘. 只有把n-1个圆盘从a->b,最后把a上剩余的一个圆盘从a->c. 之后把b上的n-1个圆盘从b->c. 这里的两步:把n-1个圆盘从a->c,和n-1个圆盘从b->c.所需要的步骤数.实际上就是把n-1个圆盘从a移动到c的步骤数*2,因为是等价的.从a->b和从b->c移动的圆盘个数都是一样的,所以步数就是 (n-1)

BZOJ5300 [Cqoi2018]九连环 【dp + 高精】

题目链接 BZOJ5300 题解 这题真的是很丧病,,卡高精卡到哭 我们设\(f[i]\)表示卸掉前\(i\)个环需要的步数 那么 \[f[i] = 2*f[i - 2] + f[i - 1] + 1\] 直接高精递推不仅\(MLE\)而且\(TLE\) 然后就要用到数学求通项公式,或者打表找规律 \[f[n] = \lfloor \frac{2^(n + 1)}{3} \rfloor\] 高精乘低精就可以过了 #include<algorithm> #include<iostream&

【POJ】3378 Crazy Thairs(树状数组+dp+高精)

题目 传送门:QWQ 分析 题意:给个数列,求有多少五元上升组 考虑简化一下问题:如果题目求二元上升组怎么做. 仿照一下逆序对,用树状数组维护一下就ok了. 三元怎么做呢? 把二元的拓展一位就可以了,即把第三个也扔进树状数组 所以这题就渐渐明朗了: 用$ dp[i][x] $表示以$ A[x] $结尾的$ x $元上升组有多少个 那么: $ dp[i][x]=\sum_{j=1}^{i-1} dp[j][x-1] (A[j]<A[i]) $ 其中 $ dp[i][1]=1 $ 因为多了一位大的就

POJ 1202 Family 概率,DP,高精 难度:2

http://poj.org/problem?id=1202 难度集中在输出格式上,因为输出格式所以是高精度 递推式: 血缘肯定只有从双亲传到儿子的,所以,设f,m为双亲,son为儿子,p[i][j]为i和j之间的血缘关系,p[j][i]=p[i][j] 则: p[son][f]=p[son][m]=0.5+0.5*p[f][m] 对于兄弟和其他不是双亲的节点j,则有 p[son][j]=0.5*(p[f][j]+p[m][j]) 另外:http://swerc.up.pt/2002/Data/

高精阶乘

求n!.当n很大的时候,会超出整数的范围. 这里用数组来进行高精阶乘.a[1]是个位,a[2]是十位......依次类推.每次要乘一个数的时候,就从个位(即a[1])开始乘这个数,>10的时候要%10再进位. 1 #include<cstdio> 2 #include<cstring> 3 const int N=100000; 4 5 int a[N]; 6 int i, j, n; 7 int t, pos/*位数*/, carry/*进位*/; 8 9 int main

动态规划学习系列——划分DP(三)

划分DP第三题,wikioi 1040,送我n个WA~~~ 题目大意: 这道题题述有着UVA的特色,够废话,其实就是读入一个长度最大200的字符串(不知道为何要分行输入,完全没有意义啊),分成m部分,使各部分单词量加起来最大 解题思路: 这题划分的部分跟乘积最大那题其实很像,状态转移方程也很容易想到: dp[i][k]=max(dp[i][k],dp[j][k-1]+scnt[j+1][i]) ( j >= k-1 ) scnt数组:scnt[j][i] 表示区间 j~i 所包含的单次总数 接下

划分DP:乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提高组

乘积最大   题目描述  Description 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加.活动中,主持人给所有参加活动的选手出了这样一道题目: 设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大. 同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子: 有一个数字串

codevs1085数字游戏(环形DP+划分DP )

1085 数字游戏 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数k.游戏的要求是使你所得的k最大或者最小. 例如,对于下面这圈数字(n=4,m=2): 2