Gym 101196F Removal Game
阿新 • • 發佈:2020-07-24
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); } }