1. 程式人生 > >Gym - 101196:F Removal Game(區間DP)

Gym - 101196:F Removal Game(區間DP)

lse 常數 pan names namespace 通過 %d 給定 style

題意:一個環狀數組,給定可以刪去一個數,代價的相鄰兩個數的gcd,求最小代價。

思路:區間DP即可,dp[i][j]表示[i,j]區間只剩下i和j時的最小代價,那麽dp[i][j]=min dp[i][k]+dp[k][j]+gcd(a[[i],a[j])。帶上註意不能加倍做,以為常數會乘8,TLE。這也是這道題通過率低的原因。

#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
const int inf=1e9+7;
int dp[maxn][maxn],a[maxn];
int main()
{
    
int N,i,j,k,ans; while(~scanf("%d",&N)&&N){ for(i=1;i<=N;i++) for(j=1;j<=N;j++) dp[i][j]=inf; for(i=1;i<=N;i++) scanf("%d",&a[i]); for(j=1;j<N;j++){ for(i=1;i<=N;i++){ if(j==1){ if(i+j==N) dp[i][N]=0
; else dp[i][(i+j)%N]=0; } else for(k=i+1;k<i+j;k++){ int tj=(i+j)%N; if(!tj) tj=N; int tk=k%N; if(!tk) tk=N; dp[i][tj]=min(dp[i][tj],dp[i][tk]+dp[tk][tj]+__gcd(a[i],a[tj])); } } } ans
=dp[1][N]+__gcd(a[1],a[N]); for(i=1;i<=N;i++) for(j=i+1;j<=N;j++) ans=min(ans,dp[i][j]+dp[j][i]+__gcd(a[i],a[j])); printf("%d\n",ans); } return 0; }

Gym - 101196:F Removal Game(區間DP)