1043 数字游戏
因为前缀和本来就是优化动态规划的方法,所以这一道题两个都得会,但是看第一眼的时候不明白和前缀和有什么关系
题目比较难理解
给定一个环数,要求分成k个方案,使得每个组的乘积之和最小和最大
首先我来列举一下操作吧
1.破环为链,这个操作非常的经典,而且在这个题很容易的看出来,给的数就是一个环,就是把数据进行两遍存储,如果想加深对破环为链的操作,必须得明白并查集的反集这一个东西,本菜鸡昨天才真正的启发式了
2.前缀和,前缀和不是万能的,但是前缀和真的很方便,节省了不少时间,适用于数据直接相加的题目,比如这个小可爱
另外我们在设计状态的时候加上一个枚举组数就好了
-----------------重新----------------------
先来说说题意:
给定一个环,给定n个数,将其分为m份
这m份的数相加,这m个结果的个数相乘,然后问这个最大最小是多少
破环为连
意思就是这个环形我们需要将其转化成一个线性的
其实这个题环不环不都一样吗,没什么区别
还有就是破环的区别就是在于首尾值的不变,所以我们需要将数组进行复制一份
1 2 3 1 2 3 这就是环的妙处
((a%10)+10)%10;//取各个位,为什么要+10进行取模?23%10=3 3+10=13 13%10=3
不影响操作,但比较保险
所以呢,这样的分割问题,什么划分了,规划了,分割了,都是需要枚举的
maxx[l][r][i] minn[l][r][i]分别表示l~r区间分割i的最大最小值
然后
min(minn[l][r][i],minn[l][k][i-1]*mod(a[r]-a[k])) 就是分割的方式
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
const int inf=2147483647;
const int SIZE=1e2+5;
int a[SIZE];
int minn[SIZE][SIZE][SIZE],maxx[SIZE][SIZE][SIZE];
int n,m;
int mod(int a)
{
return ((a%10)+10)%10;//取各个位
//为什么要+10进行取模?
//23%10=3 3+10=13 13%10=3
//不影响操作,但比较保险
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i+n]=a[i];//破环
//1 2 3 1 2 3
}
for(int i=1;i<=2*n;i++)
a[i]+=a[i-1];//循环计算前缀和
for(int l=1;l<=2*n;l++)
for(int r=l;r<=2*n;r++)
maxx[l][r][1]=minn[l][r][1]=mod(a[r]-a[l-1]);//l~r 分i段最大或最小值
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++)
minn[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<r;k++)//枚举间断点 枚举分割
{
minn[l][r][i]=min(minn[l][r][i],minn[l][k][i-1]*mod(a[r]-a[k]));//前缀和
maxx[l][r][i]=max(maxx[l][r][i],maxx[l][k][i-1]*mod(a[r]-a[k]));
}
int MAX=0,MIN=inf;
for(int i=1;i<=n;i++)//比较出最大的
{
MAX=max(MAX,maxx[i][i+n-1][m]);
MIN=min(MIN,minn[i][i+n-1][m]);
}
cout<<MIN<<endl<<MIN;
return 0;
}
/*
4 2
4
3
-1
2
*/