Gym101196F Removal Game

https://codeforces.com/gym/101196/attachments

环形/区间DP

先将区间复制一遍

\(f[i][j]\)表示区间\([i,j]\)删去\([i+1,j-1]\)的数的最小代价

之所以这样定义是因为这样比较好转移

\[f[i][j]=\min_{i<k<j} f[i][k]+f[k][j]+\gcd(a[i],a[j]) \]

最后枚举两个端点,再次计算\(\gcd\)即可

\[ans=\min_{1\le i<j \le n} f[i][j]+f[j][i+n]+\gcd(a[i],a[j]) \]

\(C++ Code:\)

#include<cstdio>
#include<iostream>
#define N 205
#define INF 1000000007
using namespace std;
int n,a[N],f[N][N],g[N][N];
int gcd(int x,int y)
{
	if (!y)
		return x;
	return gcd(y,x%y);
}
int main()
{
	for (;;)
	{
		scanf("%d",&n);
		if (!n)
			return 0;
		for (int i=1;i<=n;i++)
			scanf("%d",&a[i]),a[i+n]=a[i];
		int m=n << 1;
		for (int i=1;i<=m;i++)
			for (int j=1;j<=m;j++)
				g[i][j]=gcd(a[i],a[j]);
		for (int i=0;i<=m;i++)
			for (int j=0;j<=m;j++)
				f[i][j]=INF;
		for (int i=1;i<=m;i++)
			f[i][i+1]=0;
		for (int i=3;i<=n;i++)
		{
			for (int j=1;j<=m-i+1;j++)
			{
				int r=j+i-1;
				for (int k=j+1;k<r;k++)
					f[j][r]=min(f[j][r],f[j][k]+f[k][r]+g[j][r]);
			}
		}
		int ans=INF;
		for (int i=1;i<=n;i++)
			for (int j=i+1;j<=n;j++)
				ans=min(ans,f[i][j]+f[j][i+n]+g[i][j]);
		printf("%d\n",ans);
	}
}
posted @ 2020-07-24 19:07  GK0328  阅读(121)  评论(0编辑  收藏  举报