、

QOJ 9489 0100 Insertion(梦熊2026省选集训 Day7 T2)

题意

给定 \(01\) 字符串 \(S\),有一些位置可以填,求有多少填完后的 \(S^\prime\) 使得它可以从空串开始执行若干次从若干位置插入一个 \(0100\) 的操作能够生成出来。

\(|S|\leq 500\)。

思路

我们发现,如果直接取找 \(0100\) 的话我们不太好判断这个 \(01\) 的合法性。我们翻转,然后找 \(0010\),然后尝试找 \(S\) 合法的充要条件。我们不妨假设 \(0\) 的权值为 \(-1\),\(1\) 的权值为 \(3\)。那么对于必要性,显然有总和为 \(0\),且 \(1\) 的后面必然是 \(0\)。然后我们发现,一个 \(0010\) 的和也是 \(0\)。末尾显然至少要有 \(2\) 个 \(0\),然后考虑对于一个 \(1\) 而言,它的前面如果是全 \(0\) 那么无法断定当前不合法,且只要后面依旧满足前缀和为 \(0\) 也是合法的。那么之后就是 \(0\cdots010\cdots01\) 的,那么我们考虑删掉所有的 \(0100\),那么考虑如果不合法就先尽量留给后面,那么就是找到前缀最大值 \(k\geq h-1\),\(h\) 为当前前缀和。

那么我们考虑动规 \(f_{i,j,k}\) 表示现在考虑到 \(i\),前缀和为 \(j\),最大前缀和为 \(k\) 的方案数。对于 \(s_{i+1}=0\),则 \(f_{i,j,k}\rightarrow f_{i+1,j-1,k}\)。对于 \(s_{i+1}=1,s_{i+2}=0\),那么如果 \(k\geq j+3-1\) 就有 \(f_{i,j,k}\rightarrow f_{i+2,j+3-1,\max(k,j+3)}\)。初始 \(f_{0,0,0}=1\)。

我们压一下空间就时间复杂度 \(O(n^3)\),空间 \(O(n^2)\)。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=501;
const int ADD=MAXN;
const int MOD=998244353;
int n;
int F[3][MAXN*5][MAXN+5];
#define add(x,y) (((x)+=(y))>=MOD&&((x)-=MOD))
#define f(i,j,k) F[i][(j)+ADD][k]
int main(){
    #ifdef ONLINE_JUDGE
    freopen("insertion.in","r",stdin);
    freopen("insertion.out","w",stdout);
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    string s;
    cin>>n>>s;
    reverse(s.begin(),s.end());
    s=" "+s;
    f(0,0,0)=1;
    rep(i,0,n-1){
        if(s[i+1]!='1'){
            rep(j,-n+1,n){
                rep(k,0,n){
                        add(f(1,j-1,k),f(0,j,k));
                }
            }
        }
        if(s[i+1]!='0'&&i+2<=n&&s[i+2]!='1'){
            rep(j,-n,n-3){
                rep(k,max(j+2,0),n){
                    add(f(2,j+2,max(k,j+3)),f(0,j,k));
                }
            }
        }
        rep(j,-n,n){
            rep(k,0,n){
                f(0,j,k)=f(1,j,k);
                f(1,j,k)=f(2,j,k);
                f(2,j,k)=0;
            }
        }
    }
    int sm=0;
    rep(j,0,n){
        add(sm,f(0,0,j));
    }
    cout<<sm<<"\n";
    return 0;
}
posted @ 2026-09-24 14:44  tanghg  阅读(8)  评论(0)    收藏  举报