• [dp]Two Permutations 2022杭电多校第3场 1012


    There are two permutations P_1,P_2,\dots,P_nP1​,P2​,…,Pn​, Q_1,Q_2,\dots,Q_nQ1​,Q2​,…,Qn​ and a sequence RR. Initially, RR is empty. While at least one of PP and QQ is non-empty, you need to choose a non-empty array (PP or QQ), pop its leftmost element, and attach it to the right end of RR. Finally, you will get a sequence RR of length 2n2n.

    You will be given a sequence SS of length 2n2n, please count the number of possible ways to merge PP and QQ into RR such that R=SR=S. Two ways are considered different if and only if you choose the element from different arrays in a step.

    Input

    The first line contains a single integer TT (1 \leq T \leq 3001≤T≤300), the number of test cases. For each test case:

    The first line contains a single integer nn (1 \leq n \leq 300\,0001≤n≤300000), denoting the length of each permutation.

    The second line contains nn distinct integers P_1,P_2,\dots,P_nP1​,P2​,…,Pn​ (1\leq P_i\leq n1≤Pi​≤n).

    The third line contains nn distinct integers Q_1,Q_2,\dots,Q_nQ1​,Q2​,…,Qn​ (1\leq Q_i\leq n1≤Qi​≤n).

    The fourth line contains 2n2n integers S_1,S_2,\dots,S_{2n}S1​,S2​,…,S2n​ (1\leq S_i\leq n1≤Si​≤n).

    It is guaranteed that the sum of all nn is at most 2\,000\,0002000000.

    Output

    For each test case, output a single line containing an integer, denoting the number of possible ways. Note that the answer may be extremely large, so please print it modulo 998\,244\,353998244353 instead.

    Sample

    InputOutput
    2 
    3 
    1 2 3 
    1 2 3 
    1 2 1 3 2 3 
    2 
    1 2 
    1 2 
    1 2 2 1
    2 
    0

    题意: 给出两个长度为n的排列a和b,以及一个长度为2*n的序列c,求用a和b归并得到c的不同方案数。

    分析: 可以设dp[i][j]表示考虑c中前i个数字,包含a中前j个数字的合法归并方法,然后保存a中各数字出现的位置pos1[i],以及b中各数字出现的位置pos2[i],状态转移的时候由于对于确定的i,合法的状态只有两个,所以只需要更新两个状态,分别考虑c[i]来自a还是b,如果来自a,那么dp[i][pos1[c[i]]] += dp[i-1][pos1[c[i]]-1],如果来自b,那么dp[i][i-pos2[c[i]]] += dp[i-1][i-pos2[c[i]]],i-pos2[c[i]]就是此时a中匹配到的位置。不过这样空间显然是会爆掉的,所以需要滚动数组优化空间,在优化的时候要注意,理论上滚到新的一层时数组应该全部为0,但是由于循环只有一层,所以不可能多用一个for来清空数组,不过可以注意到每层最多只会改变两个位置的值,所以可以记录下改变的位置是哪两个,当下一层用完这层值后就可以将这两个位置置零。

    具体代码如下: 

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define int long long
    8. using namespace std;
    9. const int mod = 998244353;
    10. int a[300005];
    11. int b[300005];
    12. int ab[600005];
    13. int dp[2][300005];//dp[i][j]表示考虑ab中前i个包含a中前j个的方案数
    14. int pos1[300005];
    15. int pos2[300005];
    16. signed main()
    17. {
    18. int T;
    19. cin >> T;
    20. while(T--){
    21. int n;
    22. scanf("%lld", &n);
    23. for(int i = 1; i <= n; i++){
    24. scanf("%lld", &a[i]);
    25. pos1[a[i]] = i;
    26. }
    27. for(int i = 1; i <= n; i++){
    28. scanf("%lld", &b[i]);
    29. pos2[b[i]] = i;
    30. }
    31. for(int i = 0; i <= 1; i++)
    32. for(int j = 0; j <= n; j++)
    33. dp[i][j] = 0;
    34. for(int i = 1; i <= 2*n; i++)
    35. scanf("%lld", &ab[i]);
    36. int p1 = -1, p2 = -1;
    37. if(ab[1] == a[1]) dp[1][1]++, p1 = 1;
    38. if(ab[1] == b[1]) dp[1][0]++, p2 = 0;
    39. for(int i = 2; i <= 2*n; i++){
    40. //来自a
    41. dp[i&1][pos1[ab[i]]] = (dp[i&1][pos1[ab[i]]]+dp[(i-1)&1][pos1[ab[i]]-1])%mod;
    42. //来自b
    43. if(i-pos2[ab[i]] >= 0)
    44. dp[i&1][i-pos2[ab[i]]] = (dp[i&1][i-pos2[ab[i]]]+dp[(i-1)&1][i-pos2[ab[i]]])%mod;
    45. if(p1 != -1) dp[(i-1)&1][p1] = 0;
    46. if(p2 != -1) dp[(i-1)&1][p2] = 0;
    47. p1 = pos1[ab[i]];
    48. if(i-pos2[ab[i]] >= 0)
    49. p2 = i-pos2[ab[i]];
    50. else
    51. p2 = -1;
    52. }
    53. printf("%lld\n", dp[0][n]);
    54. }
    55. return 0;
    56. }

  • 相关阅读:
    c++&qt day4
    java计算机毕业设计高校实习实训管理系统源码+mysql数据库+系统+lw文档+部署
    git_05_撤销暂存区的修改
    Matlab 机器人工具箱 运动学
    微服务架构最佳实践:消息队列
    北斗导航 | 灰常详细的RAIM 基本理论(公式推导)
    【MATLAB源码-第78期】基于matlab的可见光通信不同调制方式(OOK,PPM,DPPM,DHPIM)误码率,信道容量分析。
    C#:Winfrom 实现DataGridView 自定义分页
    2021-01-01 - Review代码过程感悟
    有求必应 | 听说这个管线排布,横竖都行?
  • 原文地址:https://blog.csdn.net/m0_55982600/article/details/126017930