P1043 数字游戏-动态规划,区间dp

丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分为m个部分,各部分内的数字相加,相加所得的m个结果对10取模后再相乘,最终得到一个数kk。游戏的要求是使你所得的k最大或者最小。

例如,对于下面这圈数字(n=4,m=2):

P1043 数字游戏-动态规划,区间dp_第1张图片

要求最小值时,((2-1) mod 10)×((4+3) mod 10)=1×7=7,要求最大值时,为((2+4+3) mod 10)×(-1 mod 10)=9×9=81。特别值得注意的是,无论是负数还是正数,对10取模的结果均为非负值。

丁丁请你编写程序帮他赢得这个游戏。

https://www.luogu.org/problemnew/show/P1043

刚看这道题感觉就像是石子合并一样的水题;

但是写着写着感觉有些不对劲,因为这题需要分段,一段一段的取模,而石子合并不需要取模,所以顺序无所谓;

这样的话就只能再加一维表示分段的数量;

初始化:

首先把min,max的每个区间只分1段的值预处理出来;

之后m>2的情况,max无所谓本身就是0,min的话要把数组初始化为无穷大;

状态转移方程:

f1[l][r][i]=min(f1[l][r][i],f1[l][k][i-1]*mod(num[r]-num[k]));

f2[l][r][i]=max(f2[l][r][i],f2[l][k][i-1]*mod(num[r]-num[k]));

这样不就好啦~~~

最后一点:毕竟是化环为链了,要以长度为n重新扫一遍,取min,max。

#include
#include
#include
#include
#include
#define inf 2147483647
using namespace std;
int n,m;
int f1[101][101][11],f2[101][101][11];
int a[1001],num[1001];
int mod(int x)
{
    return ((x%10)+10)%10;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++){
        num[i]=num[i-1]+a[i];
    }
    for(int l=1;l<=2*n;l++){
        for(int r=l;r<=2*n;r++){
            f1[l][r][1]=f2[l][r][1]=mod(num[r]-num[l-1]);
        }
    }
    for(int i=2;i<=m;i++){
        for(int l=1;l<=2*n;l++){
            for(int r=l+i-1;r<=2*n;r++){
                f1[l][r][i]=inf;
            }
        }
    }
    for(int i=2;i<=m;i++){
        for(int l=1;l<=2*n;l++){
            for(int r=l+i-1;r<=2*n;r++){
                for(int k=l+i-2;k

 

你可能感兴趣的:(noip历年普及组,动态规划-区间)