[USACO16DEC]Team Building P 做题小插曲

这题其实没什么好记录的,只是因为我被一个看上去有些神奇但实际上和我做法一样的做法困扰了好久。

主要是这样的一个方程 \(f_{i, j, k} = f_{i-1, j, k} + f_{i, j-1, k} - f_{i-1, j-1, k} + f_{i-1, j-1, k-1} \times [a_i > b_j]\)

然后 zyy 神仙写下了这样的代码并发了题解

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#define mo 1000000009
using namespace std;
int a[1005],b[1005],f[12][1005][1005],n,m,p;
int main(){
    scanf("%d%d%d",&n,&m,&p);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=m;i++) scanf("%d",&b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    for (int i=0;i<=n;i++)
        for (int j=0;j<=m;j++) f[0][i][j]=1;
    for (int i=1;i<=p;i++){
        for (int j=1;j<=n;j++)
            for (int k=1;k<=m;k++)
                if (a[j]>b[k]) f[i][j][k]=f[i-1][j-1][k-1];
        for (int j=1;j<=n;j++)
            for (int k=1;k<=m;k++) f[i][j][k]=(f[i][j][k]+f[i][j][k-1])%mo;
        for (int j=1;j<=n;j++)
            for (int k=1;k<=m;k++) f[i][j][k]=(f[i][j][k]+f[i][j-1][k])%mo;
        }
    printf("%d",f[p][n][m]);
}

而我的代码是这样的

#include <iostream>
#include <algorithm>
#define int long long
const int N = 1005, P = 1000000009;
int n, m, k, a[N], b[N], f[N][N][15], K;
signed main() {
    std::cin >> n >> m >> K;
    for (int i = 1; i <= n; i++) std::cin >> a[i];
    for (int i = 1; i <= m; i++) std::cin >> b[i];
    std::sort(a+1, a+1+n), std::sort(b+1, b+1+m);
    for (int i = 0; i <= n; i++) f[i][0][0] = 1;
    for (int j = 0; j <= m; j++) f[0][j][0] = 1;
        
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 0; k <= K; k++) {
                f[i][j][k] =  (f[i-1][j][k] + f[i][j-1][k] - f[i-1][j-1][k] + P) % P;
                if (k != 0 && a[i] > b[j]) f[i][j][k] = (f[i][j][k] + f[i-1][j-1][k-1]) % P;
            }
    std::cout << f[n][m][K];
}    

主要有意下几点不同:

  1. 初始化不一样。
  2. 循环顺序不一样。
  3. 转移似乎也不一样。

然后就困扰了我很久才搞明白这三点所谓不同其实一个也不成立。

  1. 初始化:其实只是我多跑了一遍而已,人家直接就把 \(0\) 的填上了。
  2. 循环顺序 & 转移:
    其实 \(k\) 这一层的先后在这题中根本没有影响,我们的转移是一模一样的。
    容易发现我那个转移实际上是在求前缀和,所以要减去重复部分,而 zyy 神仙先将每一行前缀和之后再把前缀和前缀和,根本没有区别。
    但是在 dp 的角度来看而不从数值变换的角度来看这就有一些不同了,他的 dp 方程的意义不再是一直不变的,而是发生了转换(这也是困扰我的原因),中间时候状态变成了“FJ 的最后一个是这个,FP 用前几个和其匹配的方案数”,等到再加了一次才变回原来的状态。
启示

从纯数值角度看 dp 方程或许会有不一样的发现!

posted @ 2021-08-05 15:09  Acfboy  阅读(30)  评论(0)    收藏  举报