• Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵


    Problem Description
    Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.
    There are two types of queries:
    1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).
    2. Counting the number of distinct subsequences in the substring S[l,...,r].
     
    Input
    The first line contains an integer T, denoting the number of the test cases.
    For each test, the first line contains two integers N and Q.
    The second line contains the string S.
    Then Q lines follow, each with three integers typel and r, denoting the queries.

    1T5
    1N,Q105
    S[i]{0,1},1iN
    type{1,2}
    1lrN
     
    Output
    For each query of type 2, output the answer mod (109+7) in one line.
     
    首先考虑怎么求一个01串有多少种不同的子序列
    dp[i][0]表示考虑到第i位时以0结尾的不同的子序列个数
    dp[i][1]表示考虑到第i位时以1结尾的不同的子序列个数
    若第i+1位为1,则有:
    以01为结尾的子序列个数为dp[i][0]
    以11为结尾的子序列个数为dp[i][1]
    只有一个1的子序列个数为1
    以0为结尾的子序列个数为dp[i][0]
     
    以上4种情况统计了考虑到i+1处时所有的子序列
    于是有 dp[i+1][1]=dp[i][0]+dp[i][1]+1
       dp[i+1][0]=dp[i][0]
                (1  1  0
    (dp[i][0],dp[i][1],1)* 0  1  0   =(dp[i+1][0],dp[i+1][1],1)
                 0  1  1)
     记为A矩阵。
    若i+1位为0同理有:    
        dp[i+1][1]=dp[i][0]
        dp[i+1][0]=dp[i][0]+dp[i][1]+1
        对应矩阵为(记为B矩阵)
              1  0  0                          
              1  1  0                          
              1  0  1                          
    其次考虑优化的问题。将以上的两种转移视为矩阵,用线段树维护矩阵的乘积即可。
     
    对于将所有0换成1,1换成0的操作而言,等价于将所有A矩阵换成B,B换成A,而A和B通过交换1,2行及1,2列可互相转换,或者说,乘以初等矩阵Fs,t  ,该矩阵的逆为自身。(记其为F)
                                                                0  1  0     
                                                                1  0  0
      
                                                              0  0  1
     
     
    于是有FAFFAF……FBF……=FAAB……F,或者说,将大量0换成1,1换成0的时候只需要在乘积最外面进行一次交换1,2行与1,2列的操作。
     
    然而。。仍然TLE..估计是被卡了常数。心塞。
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    int N,Q;
    const long long int mo=1e9+7;
    char s[5010];
    int lazy[5050<<2];
    struct Matrix{
        int n,m;
        long long a[3][3];
        Matrix (){clear();}
        void clear(){
            n=m=3;
            memset(a,0,sizeof(a));
        }
        Matrix operator *(const Matrix &b) const{
            Matrix tmp;
            for (int i=0;i<n;++i)
                for (int j=0;j<b.m;++j)
                    for (int k=0;k<m;++k)
                        tmp.a[i][j]=(tmp.a[i][j]+a[i][k]*b.a[k][j])%mo;
            return tmp;
        }
    };
    Matrix A0,A1,E;
    Matrix cnt[5050<<2];
    inline void init()
    {
        A0.a[0][0]=1,A0.a[0][1]=0,A0.a[0][2]=0;
        A0.a[1][0]=1,A0.a[1][1]=1,A0.a[1][2]=0;
        A0.a[2][0]=1,A0.a[2][1]=0,A0.a[2][2]=1;
    
        A1.a[0][0]=1,A1.a[0][1]=1,A1.a[0][2]=0;
        A1.a[1][0]=0,A1.a[1][1]=1,A1.a[1][2]=0;
        A1.a[2][0]=0,A1.a[2][1]=1,A1.a[2][2]=1;
    
        E.a[0][0]=1,E.a[0][1]=0,E.a[0][2]=0;
        E.a[1][0]=0,E.a[1][1]=1,E.a[1][2]=0;
        E.a[2][0]=0,E.a[2][1]=0,E.a[2][2]=1;
    }
    inline void Pushup(int rt)
    {
        cnt[rt]=cnt[rt<<1]*cnt[rt<<1|1];
    }
    inline void build(int l,int r,int rt)
    {
        if(l==r)
        {
            if(s[l-1]-'0'==0)
            {
                cnt[rt]=A0;
            }
            else cnt[rt]=A1;
            return;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        Pushup(rt);
    }
    inline void change(Matrix &X)
    {
        swap(X.a[0][0],X.a[1][1]);
        swap(X.a[0][1],X.a[1][0]);
        swap(X.a[2][0],X.a[2][1]);
    }
    
    inline void pushdown(int rt)
    {
        if(lazy[rt])
        {
            change(cnt[rt<<1]);
            change(cnt[rt<<1|1]);
            lazy[rt<<1]^=1;
            lazy[rt<<1|1]^=1;
            lazy[rt]=0;
        }
    }
    inline void update(int a,int b,int l,int r,int rt)
    {
        if(l>=a&&r<=b)
        {
            change(cnt[rt]);
            lazy[rt]^=1;
            return;
        }
        pushdown(rt);
        int m=(l+r)>>1;
        if(a<=m) update(a,b,lson);
        if(b>m) update(a,b,rson);
        Pushup(rt);
    }
    inline void Input()
    {
        scanf("%d%d",&N,&Q);
        scanf("%s",s);
    }
    inline Matrix query(int a,int b,int l,int r,int rt)
    {
        if(l>=a&&r<=b) return cnt[rt];
        pushdown(rt);
        Matrix t1=E,t2=E;
        int m=(r+l)>>1;
        if(a<=m) t1=query(a,b,lson);
        if(b>m) t2=query(a,b,rson);
        return t1*t2;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int T,type,l,r;
        scanf("%d",&T);
        init();
        rep(t,1,T)
        {
            Input();
            build(1,N,1);
            rep(i,1,Q)
            {
                scanf("%d%d%d",&type,&l,&r);
                if(type==1)
                {
                    update(l,r,1,N,1);
                  //  rep(j,1,2*N) printf("i=%d dp%d=%lld
    ",i,j,(cnt[j].a[2][0]+cnt[j].a[2][1])%mo);
                }
                else
                {
                    Matrix tmp;
                    tmp=query(l,r,1,N,1);
                    printf("%lld
    ",(tmp.a[2][0]+tmp.a[2][1])%mo);
                }
            }
        }
        return 0;
    }
     
    代码如下:


  • 相关阅读:
    重载操作符- 友元函数- 非/模板类重载
    静态成员变量
    函数指针的使用
    高斯消元_HihoCoderOffer6_03
    多重背包(MultPack = ZeroOnePack + CompletePack)
    高斯消元
    textbox文本键盘全选
    BASE64-客户端(js)加码-服务器端(c#)解码,URL传递“汉字参数”解决方法
    Jquery获取input=text 的值
    sql server 2008 不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法
  • 原文地址:https://www.cnblogs.com/zhixingr/p/7454764.html
Copyright © 2020-2023  润新知