[HDU6155]Subsequence Count

题目大意:
  给定一个01序列,支持以下两种操作:
    1.区间反转;
    2.区间求不同的子序列数量。

思路:
  首先我们考虑区间反转,这是一个经典的线段树操作。
  接下来考虑求不同的子序列数量,在已知当前区间的情况下,我们有如下$O(n)$的动态规划:|
    $f_{i,0}=f_{i-1,0}+f_{i-1,1}+1,f_{i,1}=f_{i-1,1}//第i位为0$
    $f_{i,1}=f_{i-1,0}+f_{i-1,1}+1,f_{i,0}=f_{i-1,0}//第i位为1$
  这样的动态规划显然无法直接用线段树维护,而如果不能直接用线段树维护,上面维护的区间反转也就失去了意义。
  为了使用线段树维护这种动态规划,我们需要用矩阵表示这种递推关系。
  $\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&0&0\\1&1&0\\1&0&1\end{array}\right)$
  $\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&1&0\\0&1&0\\0&1&1\end{array}\right)$
  这样我们就可以保存每个区间的乘积,询问时直接相乘即可。

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<algorithm>
  4 inline int getint() {
  5     char ch;
  6     while(!isdigit(ch=getchar()));
  7     int x=ch^'0';
  8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
  9     return x;
 10 }
 11 inline int getdigit() {
 12     char ch;
 13     while(!isdigit(ch=getchar()));
 14     return ch^'0';
 15 }
 16 const int N=100001,mod=1e9+7;
 17 template<int SIZE>
 18 struct Matrix {
 19     int val[SIZE][SIZE];
 20     Matrix operator * (const Matrix &another) const {
 21         Matrix ret;
 22         for(int i=0;i<SIZE;i++) {
 23             for(int j=0;j<SIZE;j++) {
 24                 ret.val[i][j]=0;
 25                 for(int k=0;k<SIZE;k++) {
 26                     ret.val[i][j]+=(long long)val[i][k]*another.val[k][j]%mod;
 27                     ret.val[i][j]%=mod;
 28                 }
 29             }
 30         }
 31         return ret;
 32     }
 33     void operator *= (const Matrix &another) {
 34         *this=*this*another;
 35     }
 36     void flip() {
 37         std::swap(val[0][0],val[1][1]);
 38         std::swap(val[0][1],val[1][0]);
 39         std::swap(val[0][2],val[1][2]);
 40         std::swap(val[2][0],val[2][1]);
 41     }
 42     int calc() {
 43         return (val[2][0]+val[2][1])%mod;
 44     }
 45 };
 46 const Matrix<3> m[2]={
 47     {1,0,0,
 48      1,1,0,
 49      1,0,1},
 50     {1,1,0,
 51      0,1,0,
 52      0,1,1}
 53 };
 54 const Matrix<3> E={
 55     1,0,0,
 56     0,1,0,
 57     0,0,1
 58 };
 59 class SegmentTree {
 60     private:
 61         #define _left <<1
 62         #define _right <<1|1
 63         Matrix<3> val[N<<2];
 64         bool tag[N<<2];
 65         void push_up(const int p) {
 66             val[p]=val[p _left]*val[p _right];
 67         }
 68         void push_down(const int p) {
 69             if(!tag[p]) return;
 70             val[p _left].flip();
 71             val[p _right].flip();
 72             tag[p _left]^=true;
 73             tag[p _right]^=true;
 74             tag[p]=false;
 75         }
 76     public:
 77         void build(const int p,const int b,const int e) {
 78             tag[p]=false;
 79             if(b==e) {
 80                 val[p]=m[getdigit()];
 81                 return;
 82             }
 83             int mid=(b+e)>>1;
 84             build(p _left,b,mid);
 85             build(p _right,mid+1,e);
 86             push_up(p);
 87         }
 88         void modify(const int p,const int b,const int e,const int l,const int r) {
 89             if(b==l&&e==r) {
 90                 val[p].flip();
 91                 tag[p]^=true;
 92                 return;
 93             }
 94             push_down(p);
 95             int mid=(b+e)>>1;
 96             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r));
 97             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r);
 98             push_up(p);
 99         }
100         Matrix<3> query(const int p,const int b,const int e,const int l,const int r) {
101             if(b==l&&e==r) {
102                 return val[p];
103             }
104             push_down(p);
105             int mid=(b+e)>>1;
106             Matrix<3> ret=E;
107             if(l<=mid) ret*=query(p _left,b,mid,l,std::min(mid,r));
108             if(r>mid) ret*=query(p _right,mid+1,e,std::max(mid+1,l),r);
109             return ret;
110         }
111 };
112 SegmentTree t;
113 int main() {
114     for(int T=getint();T;T--) {
115         int n=getint(),q=getint();
116         t.build(1,1,n);
117         while(q--) {
118             int op=getint(),l=getint(),r=getint();
119             switch(op) {
120                 case 1: {
121                     t.modify(1,1,n,l,r);
122                     break;
123                 }
124                 case 2: {
125                     printf("%d\n",t.query(1,1,n,l,r).calc());
126                     break;
127                 }
128             }
129         }
130     }
131     return 0;
132 }

 

转载于:https://www.cnblogs.com/skylee03/p/7542616.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值