• 2022 百度之星程序设计大赛复赛 D.子序列2(动态dp/线段树维护矩阵)


    题目

    序列a1,a2,...ap是好序列,

    当且仅当p>=1且任意i∈[1,p),有a_{i}<k \leq a_{i+1}a_{i+1}<k \leq a_{i}

    给定长为n(n<=1e5)的序列a1,...,an(1<=ai<=n),q(q<=2e5)次询问

    每次询问给定k,l,r(1<=k<=n,1<=l<=r<=n),

    询问区间[l,r]内的子序列中有多少个是好序列

    答案对1e9+7取模

    思路来源

    比赛几分钟后才做出来,这种题做过无数次了,次次被卡

    题解

    一开始想着边转移,但是不行,需要有一个末态的概念

    所以,需要按点转移,>=k记为状态1,

    子序列矩阵可以0转移到0,1转移到1,0转移到1,1转移到0,

    其中,前两种表示本次不取,后两种只能同时有一个存在,表示之前取的是0/1,本次取的是1/0

    将k离线,建立线段树矩阵,在ai

    注意到,c[0][0]和c[1][1]均有为空的一种方案,所以答案需要恒减2

    最后几分钟就是这里没想清楚

    代码

    1. #include
    2. using namespace std;
    3. const int N=1e5+10,M=2e5+10,mod=1e9+7;
    4. const int INF=0x3f3f3f3f;
    5. int n,q,l,r,v,a[N],ans[M];
    6. vector<int>add[N];
    7. struct mat{
    8. const static int MAXN = 2;
    9. int c[MAXN][MAXN];
    10. int m, n;
    11. mat(){
    12. memset(c,0,sizeof (c));
    13. }
    14. mat(int a, int b) : m(a), n(b) {
    15. memset(c, 0, sizeof (c));
    16. }
    17. void reset(int a,int b){
    18. m=a; n=b;
    19. }
    20. void clear(){
    21. memset(c, 0, sizeof(c));
    22. }
    23. mat operator + (const mat& temp) {
    24. mat ans(m, temp.n);
    25. for (int i = 0; i < m; i ++)
    26. for (int j = 0; j < temp.n; j ++) {
    27. for (int k = 0; k < n; k ++){
    28. ans.c[i][j] = (ans.c[i][j] + 1ll * c[i][k] * temp.c[k][j] %mod)%mod;
    29. }
    30. }
    31. return ans;
    32. }
    33. }dat[N*4],y;
    34. struct node{
    35. int id,l,r;
    36. node(){
    37. }
    38. node(int a,int b,int c):id(a),l(b),r(c){
    39. }
    40. };
    41. vectorf[N];
    42. void pushup(int p){
    43. dat[p]=dat[p<<1]+dat[p<<1|1];
    44. }
    45. void init(int p,int l,int r){
    46. dat[p].c[0][1]=1;
    47. dat[p].c[1][1]=1;
    48. dat[p].c[0][0]=1;
    49. dat[p].c[1][0]=0;
    50. }
    51. void build(int p,int l,int r){
    52. dat[p].reset(2,2);
    53. if(l==r){
    54. init(p,l,r);
    55. return;
    56. }
    57. int mid=(l+r)/2;
    58. build(p<<1,l,mid);
    59. build(p<<1|1,mid+1,r);
    60. pushup(p);
    61. }
    62. void chg(int p,int l,int r,int pos){
    63. if(l==r){
    64. dat[p].c[1][0]=1;
    65. dat[p].c[0][1]=0;
    66. return;
    67. }
    68. int mid=(l+r)/2;
    69. if(pos<=mid)chg(p<<1,l,mid,pos);
    70. else chg(p<<1|1,mid+1,r,pos);
    71. pushup(p);
    72. }
    73. mat ask(int p,int l,int r,int ql,int qr){
    74. if(ql<=l&&r<=qr)return dat[p];
    75. int mid=(l+r)/2;
    76. if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
    77. if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
    78. return ask(p<<1,l,mid,ql,mid)+ask(p<<1|1,mid+1,r,mid+1,qr);
    79. }
    80. int main(){
    81. scanf("%d%d",&n,&q);
    82. for(int i=1;i<=n;++i){
    83. scanf("%d",&a[i]);
    84. add[a[i]].push_back(i);
    85. }
    86. build(1,1,n);
    87. for(int i=1;i<=q;++i){
    88. int k,l,r;
    89. scanf("%d%d%d",&k,&l,&r);
    90. f[k].push_back(node(i,l,r));
    91. }
    92. for(int i=1;i<=n;++i){
    93. for(auto &x:f[i]){
    94. int id=x.id,l=x.l,r=x.r;
    95. y=ask(1,1,n,l,r);
    96. ans[id]=(1ll*y.c[0][0]+y.c[0][1]+y.c[1][0]+y.c[1][1])%mod;
    97. ans[id]=(ans[id]+mod-2)%mod;
    98. }
    99. for(auto &v:add[i]){
    100. chg(1,1,n,v);
    101. }
    102. }
    103. for(int i=1;i<=q;++i){
    104. printf("%d\n",ans[i]);
    105. }
    106. return 0;
    107. }

  • 相关阅读:
    六张图详解LinkedList 源码解析
    AB实验:科学归因与增长的利器
    【Java】三大集合容器概述
    gin 模版
    php 进程通信系列 (四)共享内存
    MySQL读写分离之一主一从
    <HarmonyOS第一课>从简单的页面开始——闯关习题及答案
    Direct3D中的绘制
    LAS Spark 在 TPC-DS 的优化揭秘
    关于#html5#的问题:设计一个真正的大数据与科技传播的响应式网站(相关搜索:设计网站)
  • 原文地址:https://blog.csdn.net/Code92007/article/details/126822411