【解题报告】洛谷P1043 数字游戏

【解题报告】洛谷P1043 数字游戏

题目链接

https://www.luogu.com.cn/problem/P1043

思路

动态规划,类似于能量项链和石子合并之类的

首先这是一个环,我们用常见的破环成链的技巧——开双倍数组来做

然后我们设置状态 \(f[i][j]\) 表示前 \(i\) 个数字分成 \(j\) 个部分可以得到的最小值是多少

则有

\[f[i][j]=min\{f[i-k][j-1]\times s[i-k+1][i] \},0 \le k \le i \]

同理,我们可以设 \(g[i][j]\) 表示上述的最大值

\[g[i][j]=min\{g[i-k][j-1]\times s[i-k+1][i] \},0 \le k \le i \]

但是有一个小细节要处理一下

我们在模的时候负数模一个数字还是负数

但是根据题目描述,它要变成正数

所以我们的对于小于0的加一个10就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int maxn=105;
int n,m;
int a[maxn];
int s[maxn][maxn],f[maxn][maxn],g[maxn][maxn];
int minn=1e9,maxx=-1e9;

signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		a[i+n]=a[i];
	}
	for(int x=0;x<=n;x++)
	{
		for(int i=x+1;i<=x+n;i++)
		{
			for(int j=i;j<=x+n;j++)
			s[i][j]=s[i][j-1]+a[j];
		}
		for(int i=x+1;i<=x+n;i++)
		{
			for(int j=i;j<=x+n;j++)
			{
				s[i][j]%=10;
				if(s[i][j]<0) 
				s[i][j]+=10;
			}
		}
		for(int i=x+1;i<=x+n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				f[i][j]=1e9;
				g[i][j]=-1e9;
			}
		}
		for(int i=x+1;i<=x+n;i++)
		f[i][0]=g[i][0]=s[x+1][i];
		for(int j=1;j<=m;j++)
		{
			for(int i=j+1+x;i<=n+x;i++)
			{
				for(int k=x+1;k<i;k++)
				{
					f[i][j]=min(f[i][j],f[k][j-1]*s[k+1][i]);
					g[i][j]=max(g[i][j],g[k][j-1]*s[k+1][i]);
				}
			}
		}
		maxx=max(maxx,g[x+n][m-1]);
		minn=min(minn,f[x+n][m-1]);
	} 
	cout<<minn<<'\n'<<maxx<<'\n';
	return 0;
}
posted @ 2021-10-20 10:58  wweiyi  阅读(30)  评论(0编辑  收藏  举报
js脚本