1388. 游戏

状态表示:
\(f[i][j]\) 表示在区间 \([i,j]\) 时,先手和后手的最大差值得分。

状态转移:

  • 当取 \(w[i]\) 时,\(f[i][j]=w[i]−f[i+1][j]\)
  • 当取 \(w[j]\) 时,\(f[i][j]=w[j]−f[i][j−1]\)

\(f[i][j]\) 表示在区间为 \([i, j]\) 时 A 与 B 得分差的最大值,则\(f[i + 1][j]\) 表示区间为 \([i + 1, j]\) 时 B 与 A 得分差的最大值,取一下相反数即可得到区间为\([i+1, j]\)时 A 与 B 得分差的最大值。

边界:
\(f[i][i] = w[i]\)

const int N = 110;
int a[N];
int f[N][N];
int n;

int main()
{
    cin >> n;

    int sum = 0;
    for(int i = 1; i <= n; i++) cin >> a[i], sum += a[i];

    for(int i = n; i; i--)
        for(int j = 1; j <= n; j++)
            if(i == j) f[i][j] = a[i];
            else f[i][j] = max(a[i] - f[i + 1][j], a[j] - f[i][j - 1]);
            
    cout << (sum + f[1][n]) / 2 << ' ' << (sum - f[1][n]) / 2 << endl;
    //system("pause");
    return 0;
}

另解

状态表示:
\(f[i][j]\)表示区间为\([i,j]\)时先手得分的最大值。

状态转移:

  • 当取 \(w[i]\) 时,则 \(f[i][j]=w[i]+∑jk=i+1w[k]−f[i+1][j]\)
  • 当取 \(w[j]\) 时,则 \(f[i][j]=w[j]+∑j−1k=iw[k]−f[i][j−1]\)

边界:
\(f[i][i] = w[i]\)

const int N = 110;
int a[N];
int sum[N];
int f[N][N];
int n;

int main()
{
    cin >> n;

    for(int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i - 1] + a[i];

    for(int i = n; i; i--)
        for(int j = 1; j <= n; j++)
            if(i == j) f[i][j] = a[i];
            else f[i][j] = max(a[i] + sum[j] - sum[i] - f[i + 1][j], a[j] + sum[j - 1] - sum[i - 1] - f[i][j - 1]);
            
    cout << f[1][n] << ' ' << sum[n] - f[1][n] << endl;
    //system("pause");
    return 0;
}
posted @ 2021-06-26 11:10  Dazzling!  阅读(23)  评论(0编辑  收藏  举报