• 杭电多校第三场补题记录


    A Equipment Upgrade

    题意:有一个人从 0 0 0 要走到 n n n,在 x = i , i ∈ [ 0 , n − 1 ] x=i,i \in [0,n-1] x=i,i[0,n1] 处可以花费 c i c_i ci 的代价,有 p i p_i pi 的概率走到 x = i + 1 x=i+1 x=i+1;然后给定长度为 n − 1 n-1 n1 的权值数组 { w i } \{w_i\} {wi} 表示往下掉 i i i 步的概率,即在 x = i x=i x=i 处有 w j ∑ k = 1 i w k \displaystyle \dfrac{w_j}{\sum_{k=1}^i w_k} k=1iwkwj 的概率落到 i − j i-j ij 处。问期望走到 n n n 所花费的代价。 n ≤ 1 × 1 0 5 n \leq 1\times 10^5 n1×105

    解法:设 F i F_i Fi 表示从 0 0 0 走到 i i i 的期望代价。考虑 x = i x=i x=i 处转移到 F i + 1 F_{i+1} Fi+1 的情况:

    1. p i p_i pi 的概率走到 i + 1 i+1 i+1
    2. 1 − p i 1-p_i 1pi 的概率不断往下掉再爬回来。

    W W W 为已经确认掉下去了,再爬回来的期望代价,则有:
    F i + 1 = ∑ j = 0 + ∞ p i ( 1 − p i ) j ( ( 1 + j ) c i + j W ) = c i p i + p i c i W ∑ j = 0 + ∞ ( 1 − p i ) j j = c i p i + 1 − p i p i c i W

    Fi+1=j=0+pi(1pi)j((1+j)ci+jW)=cipi+piciWj=0+(1pi)jj=cipi+1pipiciW" role="presentation" style="position: relative;">Fi+1=j=0+pi(1pi)j((1+j)ci+jW)=cipi+piciWj=0+(1pi)jj=cipi+1pipiciW
    Fi+1===j=0+pi(1pi)j((1+j)ci+jW)pici+piciWj=0+(1pi)jjpici+pi1piciW
    考虑 W W W 的构成。对于掉到 i − j i-j ij,其概率为 w j ∑ k = 1 i w k \dfrac{w_j}{\sum_{k=1}^i w_k} k=1iwkwj,再从 i − j i-j ij 回到 i i i 的期望代价为 f i − f j f_i-f_j fifj。因而 W = 1 ∑ k = 1 i w k ∑ j = 1 i w j ( F i − F i − j − 1 ) = F i − 1 ∑ k = 1 i w k ∑ j = 1 i w j F i − j − 1 \displaystyle W=\dfrac{1}{\sum_{k=1}^i w_k}\sum_{j=1}^iw_j(F_i-F_{i-j-1})=F_i-\dfrac{1}{\sum_{k=1}^i w_k}\sum_{j=1}^{i}w_{j}F_{i-j-1} W=k=1iwk1j=1iwj(FiFij1)=Fik=1iwk1j=1iwjFij1

    因而最终化简的式子为 F i + 1 = c i + F i p i + 1 − p i p i ∑ k = 1 i w k ∑ j = 1 i w j F i − j − 1 \displaystyle F_{i+1}=\dfrac{c_i+F_i}{p_i}+\dfrac{1-p_i}{p_i\sum_{k=1}^i w_k}\sum_{j=1}^i w_jF_{i-j-1} Fi+1=pici+Fi+pik=1iwk1pij=1iwjFij1。这是一个典型的半在线卷积形式,因而使用分治 NTT 可以 O ( n log ⁡ 2 n ) \mathcal O(n \log^2n) O(nlog2n) 通过本题。

    B Boss Rush

    题意:有 n n n 个技能,每个技能使用完成之后有 t i t_i ti 秒的冷却时间,以及一个长度为 l i l_i li 的序列 { d i } \{d_i\} {di} 表示这个技能接下来的 l i l_i li 秒中,每一秒这个技能对敌人的伤害。给定敌人的血量 H H H,问在每个技能至多使用一次的情况下,至少使用多长时间才能将敌人击杀,或者报告不能击杀。 n ≤ 18 n \leq 18 n18 ∑ l i ≤ 3 × 1 0 5 \sum l_i \leq 3\times 10^5 li3×105 H ≤ 1 × 1 0 18 H \leq 1\times 10^{18} H1×1018

    解法:显然伤害对时间是单调递增的,且为了尽快击杀,技能是连续释放的。同时由于 n n n 非常小,考虑二分答案套状态压缩。二分击杀时间 T T T,设 f S f_{S} fS 表示技能使用情况为 S S S,在 t t t 时刻前所能打出的最大伤害。记 t S t_S tS 为使用 S S S 这些技能所用时间,则枚举未使用的技能 i i i,其开始使用时间为 t s t_s ts i i i 技能所能打出的伤害秒数为 j = min ⁡ ( T − t S , l i ) j=\min(T-t_S,l_i) j=min(TtS,li),则伤害利用 { d i } \{d_i\} {di} 的前缀和可以 O ( 1 ) \mathcal O(1) O(1) 的计算。因而 f S ∪ i ← max ⁡ i ∉ S { f S + ∑ k = 0 j d i , k } \displaystyle f_{S \cup i} \leftarrow \max_{i \not \in S}\left \{f_S+\sum_{k=0}^jd_{i,k}\right \} fSiiSmax{fS+k=0jdi,k}。总时间复杂度 O ( n 2 n log ⁡ ∑ l i ) \mathcal O(n2^n \log \sum l_i) O(n2nlogli)

    此题使用二分的核心在于:如果时间不知道,那么每个技能所能打出伤害的时间是不可知的,因而非常不好转移。本题卡常。

    #include 
    using namespace std;
    const long long inf = 0x3f3f3f3f3f3f3f3fll;
    const int N = 1 << 18, M = 100000;
    int oldtime[N];
    long long f[N], t[20];
    long long d[20][M + 5], h;
    int len[20], n;
    bool check(int val)
    {
        for (int i = 0; i < 1 << n;i++)
            f[i] = 0;
        for (int i = 1; i < 1 << n; i++)
            for (int j = 0; j < n; j++)
                if (i & (1 << j))
                {
                    int old = i ^ (1 << j);
                    if (oldtime[old] > val)
                        continue;
                    int hitlen = min(len[j] - 1, val - oldtime[old]);
                    f[i] = max(f[i], f[old] + d[j][hitlen]);
                }
        for (int i = 0; i < 1 << n; i++)
            if (f[i] >= h)
                return true;
        return false;
    }
    int main()
    {
        int test;
        scanf("%d", &test);
        while(test--)
        {
            scanf("%d%lld", &n, &h);
            for (int i = 0, x; i < n;i++)
            {
                scanf("%d%d", &t[i], &len[i]);
                for (int j = 0; j < len[i];j++)
                {
                    scanf("%lld", &d[i][j]);
                    if(j)
                        d[i][j] += d[i][j - 1];
                }
            }
            long long all = 0;
            for (int i = 0; i < n;i++)
                all += d[i][len[i] - 1];
            if(all < h)
            {
                printf("-1\n");
                continue;
            }
            for (int i = 0; i < 1 << n;i++)
            {
                oldtime[i] = 0;
                for (int j = 0; j < n;j++)
                    if (i & (1 << j))
                        oldtime[i] += t[j];
            }
            int left = 0, right = 5e6, ans = -1;
            while (left <= right)
            {
                int mid = (left + right) >> 1;
                if (check(mid))
                {
                    ans = mid;
                    right = mid - 1;
                }
                else
                    left = mid + 1;
            }
            printf("%lld\n", ans);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    C Cyber Language

    题意:对于一串用空格分隔的若干字符串,将其首字母大写。

    解法:直接模拟即可。

    E Spanning Tree Game

    题意:给定一个 n n n 个点 m m m 条边的联通无向图,和两个长度为 m m m 的序列 { a i } \{a_i\} {ai} { b i } \{b_i\} {bi},求出:对于 k ∈ [ 0 , m ] k \in [0,m] k[0,m],Alice 从 m m m 条边中选取 k k k 条边 { e 1 , e 2 , ⋯   , e k } \{e_1,e_2,\cdots,e_k\} {e1,e2,,ek},它们的权值为 { a e 1 , a e 2 , ⋯   , a e k } \{a_{e_1},a_{e_2},\cdots,a_{e_k}\} {ae1,ae2,,aek},对于剩下的边 { e k + 1 , e k + 2 , ⋯   , e m } \{e_{k+1},e_{k+2},\cdots,e_m\} {ek+1,ek+2,,em},其权值为 { b e k + 1 , b e k + 2 , ⋯   , b e m } \{b_{e_{k+1}},b_{e_{k+2}},\cdots,b_{e_m}\} {bek+1,bek+2,,bem},Bob 对于这张带权图求最小生成树,Alice 希望生成树权值尽可能大,问这颗树的最大权值。 n ≤ 9 n \leq 9 n9 m ≤ 30 m \leq 30 m30

    解法:考虑将每条边拆成两个: ( u i , v i , a i ) (u_i,v_i,a_i) (ui,vi,ai) ( u i , v i , b i ) (u_i,v_i,b_i) (ui,vi,bi),若 a i ≥ b i a_i \geq b_i aibi 则存入 ( u i , v i , b i , − 1 ) , ( u i , v i , a i , 0 ) (u_i,v_i,b_i,-1),(u_i,v_i,a_i,0) (ui,vi,bi,1),(ui,vi,ai,0);若 a i < b i a_iai<bi,则存入 ( u i , v i , a i , 1 ) , ( u i , v i , b i , 0 ) (u_i,v_i,a_i,1),(u_i,v_i,b_i,0) (ui,vi,ai,1),(ui,vi,bi,0)。最后一个参数的含义为,选择这条边会让选择的 a a a 集合个数变化量。

    首先依照 Kruskal 对所有边排序,依照权值为第一关键字,集合变化量为第二关键字, 0 0 0 边后置。依次对所有的边进行遍历,考虑枚举到的边有以下三种情况:

    1. ( u , v , w , 1 ) (u,v,w,1) (u,v,w,1),则此边是不一定需要的(后面还有同样的边)。若 u , v u,v u,v 不连通则权值增加 w w w,且 a a a 数组选的个数增加 1 1 1
    2. ( u , v , w , − 1 ) (u,v,w,-1) (u,v,w,1),则此边是不一定需要的(后面还有同样的边)。若 u , v u,v u,v 不连通则权值增加 w w w,且 a a a 数组选的个数减少 1 1 1
    3. ( u , v , w , 0 ) (u,v,w,0) (u,v,w,0)。则 ( u , v ) (u,v) (u,v) 边已经被考虑过了。若之前的那条边没选,且 ( u , v ) (u,v) (u,v) 不连通,则此边必选;若已经选了,增加这条边显然树权值不会减小。因而只需要考虑未连通的情况下权值增加 w w w,且 a a a 数组选的个数不变。

    考虑所有的图连通情况,即是将 n n n 个数分到若干个集合,集合非空。这一方案数为 ∑ i = 1 n { n i } = ϖ n \displaystyle \sum_{i=1}^n {n \brace i}=\varpi_n i=1n{in}=ϖn,注意到 ϖ 9 = 21147 \varpi_9=21147 ϖ9=21147,因而设置 dp 数组: f i , j , k f_{i,j,k} fi,j,k 表示对于前 i i i 条边,连通状态为 j j j,且 a a a 集合选取了 k k k 条边的最大权值,每次的 dp 转移都是 O ( 1 ) \mathcal O(1) O(1),使用滚动数组优化空间,总的时间复杂度为 O ( m 2 ϖ n ) \mathcal O(m^2 \varpi_n) O(m2ϖn)

    F Dusk Moon

    题意:平面上有 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi),有以下 q q q 次、两种操作:

    1. 将第 j j j 个点移动到 ( x ′ , y ′ ) (x',y') (x,y)
    2. 查询区间 [ l , r ] [l,r] [l,r] 构成的点集合 { ( x l , y l ) , ( x l + 1 , y l + 1 ) , ⋯   , ( x r , y r ) } \{(x_l,y_l),(x_{l+1},y_{l+1}),\cdots,(x_r,y_r)\} {(xl,yl),(xl+1,yl+1),,(xr,yr)} 的最小圆覆盖。

    n , q ≤ 1 × 1 0 5 n,q \leq 1\times 10^5 n,q1×105,点随机给出。

    解法:对于随机给出的 n n n 个点,其期望的凸包点数为 O ( log ⁡ n ) O(\log n) O(logn) 个的。因而使用线段树暴力维护区间 [ l , r ] [l,r] [l,r] 的凸包点集,对于子区间的合并可以每次暴力使用 Andrew 算法重新计算,然后使用随机情况下 O ( n ) O(n) O(n) 的最小圆覆盖算法,总的时间复杂度为 O ( q log ⁡ 2 n log ⁡ log ⁡ n ) \mathcal O(q\log^2 n \log \log n) O(qlog2nloglogn)。或者可以归并排序的写法,减去 Andrew 算法的排序,减少这一 log ⁡ log ⁡ n \log \log n loglogn。本题卡常。

    I Package Delivery

    题意:有 n n n 个包裹,每个包裹取件时间为 [ l i , r i ] [l_i,r_i] [li,ri]。可以在任意一天取任意多次包裹,每次至多取 k k k 个包裹,问最少取多少次包裹。 1 ≤ k ≤ n ≤ 1 × 1 0 6 1 \leq k \leq n \leq 1\times 10^6 1kn1×106

    解法:考虑贪心,显然需要在最晚的一天取尽可能多的包裹。

    首先对于所有的区间,按左端点 l l l 排序。同时维护一个堆,表示现在可以取的包裹,堆内按 r r r 排序。按右端点先后枚举区间,每次取出还未取走的最小的 r r r 的那个包裹,将还未塞入堆中的所有满足 l i ≤ r l_i \leq r lir 的包裹全部塞进堆中,在堆内找到 r r r 最小的 k k k 个包裹(或取空)取走,并且必须保证当前这个枚举的包裹被取走。

    总时间复杂度为 O ( n log ⁡ n ) \mathcal O(n \log n) O(nlogn)

    #include 
    using namespace std;
    struct node
    {
        int l, r;
        int id;
        bool operator<(const node &b)const
        {
            return r > b.r;
        }
    };
    int main()
    {
        int t, n, k;
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d%d", &n, &k);
            vector<node> que(n);
            for (int i = 0; i < n;i++)
            {
                scanf("%d%d", &que[i].l, &que[i].r);
                que[i].id = i;
            }
            vector<int> vis(n, 0);
            vector<node> quer = que;
            auto cmpl = [&](node a, node b)
            {
                return a.l < b.l;
            };
            auto cmpr = [&](node a, node b)
            {
                return a.r < b.r;
            };
            sort(que.begin(), que.end(), cmpr);
            sort(quer.begin(), quer.end(), cmpl);
            priority_queue<node> q;
            int ans = 0, place = 0;
            for (int i = 0; i < n;i++)
            {
                if(vis[que[i].id])
                    continue;
                while (place < n && quer[place].l <= que[i].r)
                    q.push(quer[place++]);
                int cnt = 0;
                while(!q.empty() && cnt + (!vis[q.top().id]) <= k)
                {
                    cnt += (!vis[q.top().id]);
                    vis[q.top().id] = 1;
                    q.pop();
                }
                ans++;
                if(!vis[que[i].id])
                    i--;
            }
            if(!q.empty())
                ans += (q.size() + k - 1) / k;
            printf("%d\n", ans);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    K Taxi

    题意:给定平面上 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi) 和权值 w i w_i wi,任意一个点 ( x , y ) (x,y) (x,y) 到它的代价为 min ⁡ ( w i , ∣ x − x i ∣ + ∣ y − y i ∣ ) \min(w_i,|x-x_i|+|y-y_i|) min(wi,xxi+yyi) q q q 次询问,每次给出一个点 ( x , y ) (x,y) (x,y),问到这 n n n 个点的最大权值。 n , q ≤ 5 × 1 0 5 n,q \leq 5\times 10^5 n,q5×105

    解法:单纯考虑 ∣ x − x i ∣ + ∣ y − y i ∣ |x-x_i|+|y-y_i| xxi+yyi,拆开绝对值可以分成 4 4 4 个情况—— x + y + max ⁡ ( − x i − y i ) x+y+\max(-x_i-y_i) x+y+max(xiyi) x − y + max ⁡ ( − x i + y i ) x-y+\max(-x _i+y_i) xy+max(xi+yi) − x + y + max ⁡ ( x i − y i ) -x+y+\max(x_i-y_i) x+y+max(xiyi) − x − y + max ⁡ ( x i + y i ) -x-y+\max(x_i+y_i) xy+max(xi+yi),依次分开维护 max ⁡ ( − x i − y i ) , max ⁡ ( x i − y i ) , max ⁡ ( − x i , y i ) , max ⁡ ( x i + y i ) \max(-x_i-y_i),\max(x_i-y_i),\max(-x_i,y_i),\max(x_i+y_i) max(xiyi),max(xiyi),max(xi,yi),max(xi+yi) 即可。

    考虑引入 w w w——按 w w w 排序从小到大排序,再加入 ∣ x − x i ∣ + ∣ y − y i ∣ |x-x_i|+|y-y_i| xxi+yyi 的限制,即是在 w w w 这一参数单调递增的情况下维护这四个权值的后缀最大值。预处理后可以做到 O ( 1 ) \mathcal O(1) O(1) 查询曼哈顿距离最大值。

    考虑单调性:后缀最大值单调递减, w w w 单调递增,对这两个取 min ⁡ \min min 后必然有一单峰。因而使用二分——对于一个分界点 k k k,首先查询后缀 k k k 的曼哈顿距离最大值 d k d_k dk,和权值最小值 w k w_k wk,若 d k ≤ w k d_k \leq w_k dkwk 则表示 w w w 不对会曼哈顿距离的最大值造成影响,分界点可以向前;否则 w k w_k wk 就会影响答案,需要继续向后移动 k k k。利用这一隐藏的单调性可以做到单次询问 O ( log ⁡ n ) \mathcal O(\log n) O(logn)

    #include 
    using namespace std;
    struct node
    {
        long long x, y;
        long long w;
        bool operator<(const node &b)const
        {
            return w < b.w;
        }
    };
    int main()
    {
        int t, n, q;
        long long x, y;
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d%d", &n, &q);
            vector<node> que(n);
            for (int i = 0; i < n;i++)
                scanf("%lld%lld%lld", &que[i].x, &que[i].y, &que[i].w);
            sort(que.begin(), que.end());
            vector<long long> suf1(n), suf2(n), suf3(n), suf4(n);
            for (int i = n - 1; i >= 0;i--)
            {
                suf1[i] = que[i].x + que[i].y;
                suf2[i] = que[i].x - que[i].y;
                suf3[i] = -que[i].x + que[i].y;
                suf4[i] = -que[i].x - que[i].y;
                if (i + 1 < n)
                {
                    suf1[i] = max(suf1[i], suf1[i + 1]);
                    suf2[i] = max(suf2[i], suf2[i + 1]);
                    suf3[i] = max(suf3[i], suf3[i + 1]);
                    suf4[i] = max(suf4[i], suf4[i + 1]);
                }
            }
            auto cal = [&](long long x, long long y, int id)
            {
                return max({suf1[id] - x - y, suf2[id] - x + y, suf3[id] + x - y, suf4[id] + x + y});
            };
            while(q--)
            {
                scanf("%lld%lld", &x, &y);
                int left = 0, right = n - 1;
                long long ans = 0;
                while (left <= right)
                {
                    int mid = (left + right) >> 1;
                    ans = max(ans, min(cal(x, y, mid), que[mid].w));
                    if (cal(x, y, mid) <= que[mid].w)
                        right = mid - 1;
                    else
                        left = mid + 1;
                }
                printf("%lld\n", ans);
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    L Two Permutations

    题意:给定两个长度为 n n n 的排列 A , B A,B A,B,进行归并,问能够归并成长度为 2 n 2n 2n 的序列 C C C,如果能输出方案数。 n ≤ 1 × 1 0 6 n \leq 1\times 10^6 n1×106

    解法:考虑一个暴力 dp: f i , j f_{i,j} fi,j 表示 A A A 序列取出 i i i 个, B B B 序列取出 j j j 个的方案数。则对于 C C C 序列已经覆盖了 i + j i+j i+j 个数。其转移为 f i , j + 1 ← f i , j [ C i + j + 1 = B j + 1 ] f_{i,j+1} \leftarrow f_{i,j}[C_{i+j+1}=B_{j+1}] fi,j+1fi,j[Ci+j+1=Bj+1] f i + 1 , j ← f i , j [ C i + j + 1 = A i + 1 ] f_{i+1,j} \leftarrow f_{i,j}[C_{i+j+1}=A_{i+1}] fi+1,jfi,j[Ci+j+1=Ai+1]。但是这个暴力其实复杂度是 O ( 4 n ) \mathcal O(4n) O(4n) 的——因为满足 C i + j + 1 = B j + 1 C_{i+j+1}=B_{j+1} Ci+j+1=Bj+1 C i + j + 1 = A i + 1 C_{i+j+1}=A_{i+1} Ci+j+1=Ai+1 的只有 4 n 4n 4n 次。因而总状态数也只有 4 n 4n 4n,可以使用记忆化搜索通过。

    #include 
    using namespace std;
    const long long mod = 998244353;
    int main()
    {
        int t, n;
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d", &n);
            unordered_map<long long, long long> f;
            vector<int> p(n + 1), q(n + 1), s(2 * n + 1);
            for (int i = 1; i <= n;i++)
                scanf("%d", &p[i]);
            for (int i = 1; i <= n;i++)
                scanf("%d", &q[i]);
            vector<int> times(n + 1, 0);
            for (int i = 1; i <= 2 * n;i++)
            {
                scanf("%d", &s[i]);
                times[s[i]]++;
            }
            bool flag = 0;
            for (int i = 1; i <= n;i++)
                if (times[i] != 2)
                {
                    flag = 1;
                    break;
                }
            if(flag)
            {
                printf("0\n");
                continue;
            }
            vector<int> memo(n + 1, -1);
            function<int(int, int, int)> dfs = [&](int x, int y, int z)
            {
                if (z == 2 * n + 1)
                    return 1;
                if (x <= n && y <= n && p[x] == q[y])
                {
                    if (p[x] == s[z])
                    {
                        if(memo[p[x]] == -1)
                            return memo[p[x]] = (dfs(x + 1, y, z + 1) + dfs(x, y + 1, z + 1)) % mod;
                        else
                            return memo[p[x]];
                    }
                    else
                        return 0;
                }
                if (x <= n && p[x] == s[z])
                    return dfs(x + 1, y, z + 1);
                if (y <= n && q[y] == s[z])
                    return dfs(x, y + 1, z + 1);
                return 0;
            };
            printf("%d\n", dfs(1, 1, 1));
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
  • 相关阅读:
    Java转Android:第4天 用Layout布局实现罗盘和三叉戟
    elementor引入扩展的电子商务功能
    这几种常见的 JVM 调优场景,你知道吗?
    Leetcode406. 根据身高重建队列
    链表、树和图专项练习
    汉字编码新尝试:字理组字编码方案v0.0
    你也想做一个Element-ui吧!!!——Blueの前端路(一)
    CF-Div2-832 D. Yet Another Problem(bitmask&结论)
    SpringCloud 05 Eureka集群环境配置和CAP
    Sql注入(手工注入思路、绕过、防御)
  • 原文地址:https://blog.csdn.net/m0_52048145/article/details/126016937