1. 程式人生 > >牛客網暑期ACM多校訓練營(第一場)A Monotonic Matrix LGV定理 E Removal 思維,dp

牛客網暑期ACM多校訓練營(第一場)A Monotonic Matrix LGV定理 E Removal 思維,dp

pri lin mod 不重復 牛客網 contest sdn 。。 namespace

A Monotonic Matrix

題意:
構造滿足下列3 點的矩陣,問有多少種方案。

  • Ai, j ∈ {0, 1, 2} for all 1 ≤ i ≤ n, 1 ≤ j ≤ m.
  • Ai, j ≤ Ai + 1, j for all 1 ≤ i < n, 1 ≤ j ≤ m.
  • Ai, j ≤ Ai, j + 1 for all 1 ≤ i ≤ n, 1 ≤ j < m.

題解:
考慮01 和12 的分界線,是(n, 0) 到(0, m) 的兩條不相交(可重合)路徑。
平移其中一條變成(n-1, -1) 到(-1, m-1),變成起點(n, 0) 和(n-1, -1),終點(0, m) 和(-1, m-1) 的嚴格不相交路徑。

套Lindstr?m–Gessel–Viennot lemma,答案是C(n+m, n)^2 - C(n+m, m-1) * C(n+m, n-1) 。

Lindstr?m–Gessel–Viennot lemma 定理

主要用來解決網格圖不相交路徑計數問題。
技術分享圖片


E Removal

題意:
長度為 n 的字符串,每個字符 1<=si<=k,要恰好刪去 m 個字符,問最後留下的字符串有多少種可能。
題解:
官方題解:設next(i, c) 表示位置i 後第一個字符c的位置f(i, j) 表示當前匹配到i,刪了j 個,不同的方案數轉移時枚舉下一個字符c,轉移到f(next(i, c), j+ next(i, c) -i)



太蠢了看不懂官方題解,參考大佬博客寫的。。

dp[i][j] 表示前 i 個字符,刪除了 j 個字符的不重復方案數。
如果允許重復,很容易想到轉移為 dp[i][j] = dp[i-1][j] + dp[i-1][j-1] 。
再想哪些是重復了呢?比如 {1,1,2,3,2 }, 我們刪除第4和第5個數{3,2} ,或者刪除第3和第4個數 {2,3} ,這就重復了。也就是說,對於兩個相同的數,如果它們中間有數字,那就會造成一次重復。
所以用 pre[i] 表示前一個 s[i] 的位置,dp[i][j] 減去 dp[pre[s[i]]-1] [j-(i-pre[i])] 即可。


#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 100005, mod = 1e9+7;

int n, m, K, s[N], pos[11], pre[N];
ll  dp[N][11];
void Init() {
    rep(j,0,10) pos[j] = 0;
    rep(i,0,N-1) {
        rep(j,0,10) dp[i][j]=0;
    }
    dp[0][0] = 1;
}
int main()
{
    while(~scanf("%d%d%d", &n, &m, &K))
    {
        Init();
        rep(i,1,n) {
            scanf("%d", &s[i]);
            pre[i]=pos[s[i]],  pos[s[i]]=i;
        }
        rep(i,1,n)
        {
            rep(j,0,m)
            {
                ( dp[i][j] += dp[i-1][j] ) %= mod;
                if(0<=j-1)
                    ( dp[i][j] += dp[i-1][j-1] ) %= mod;
                int num = j-(i-pre[i]);
                if(0<=num && 0<pre[i])
                    ( dp[i][j] -= dp[pre[i]-1][num] ) %= mod;
            }
        }
        printf("%lld\n", (dp[n][m]+mod)%mod);
    }

    return 0;
}

牛客網暑期ACM多校訓練營(第一場)A Monotonic Matrix LGV定理 E Removal 思維,dp