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);
}
}