AT2161 [ARC065D] シャッフル / Shuffling

https://www.luogu.com.cn/problem/AT2161

考虑DP
f [ i ] [ j ] f[i][j] f[i][j]表示考虑前 i i i位,放了 j j j 1 1 1的方案数
那么可以轻松得到转移方程

f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 1 ] f[i][j]=f[i-1][j]+f[i-1][j-1] f[i][j]=f[i1][j]+f[i1][j1]
即这一位是否放 1 1 1
但是有些状态是非法的,所以要对于每个 i i i吧合法的转移区间先提前算出来再DP

code:

#include<bits/stdc++.h>
#define N 3005
#define mod 1000000007
using namespace std;
int n, m, f[N][N], s[N], nxt[N];
char st[N];
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", st + 1);
    for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + st[i] - '0', nxt[i] = i;
    while(m --) {
        int l, r;
        scanf("%d%d", &l, &r);
        nxt[l] = max(nxt[l], r);
    }
    for(int i = 1; i <= n; i ++) nxt[i] = max(nxt[i - 1], nxt[i]);
 //   for(int i = 1; i <= n; i ++) printf("%d ", nxt[i]); printf("\n");
    f[0][0] = 1;
    for(int i = 1; i <= n; i ++) {
        int r = min(i, s[nxt[i]]);
        int l = max(0, i - (nxt[i] - s[nxt[i]]));
        for(int j = l; j <= r; j ++) {
            f[i][j] = (f[i][j] + f[i - 1][j]) % mod;
            if(j) f[i][j] = (f[i][j] + f[i - 1][j - 1]) % mod;
        }
     //   for(int j = 0; j <= n; j ++) printf("%d ", f[i][j]); printf("   %d %d\n", l, r);
    }
    printf("%d", f[n][s[n]]);
    return 0;
}

posted @ 2021-10-13 07:22  lahlah  阅读(32)  评论(0编辑  收藏  举报