zoukankan      html  css  js  c++  java
  • HDU6155 Subsequence Count

    题意:找子区间的子序列,多种操作,多种查询,操作为翻转区间01串;

    思路:线段树维护区间矩阵;

    首先看递推方程:当是s[i]=0时dp[i][0]=dp[i-1][0]+dp[i-1][1]+1,dp[i][1]=dp[i-1][1];为一的时候同理,再次发现我们需要一个三维矩阵来更新递推式,那我们来变换一下式子,dp[i][0]+1=dp[i-1][0]+1+dp[i-1][1]+1,dp[i][1]+1=dp[i-1][1]+1;那我们发现三维矩阵变成二维的了,则复杂度便从3^3降为2^2(矩阵乘积时候),接下来又发现,s[i]=0,s[i]=1的时候递推矩阵刚好是第一行变为第二行,第一列变为第二列,如此,当一个区间内的01串翻转之后相当于区间的矩阵第一行变为第二行,第一列变为第二列,对此可能不好想到,不过可以用矩阵初等变换推出,因此,每次区间翻转只需要转换一下矩阵即可,代码算是比较优化的:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define L l , m , u << 1
    #define R m + 1 , r , u << 1 | 1
    typedef long long LL;
    const int maxn=1e5+100;
    const LL mod=1e9+7;
    char s[maxn];
    struct Matrix
    {
        LL v[2][2];
        void init(int g)
        {
            if(g)v[0][0]=v[0][1]=v[1][1]=1,v[1][0]=0;
            else v[0][0]=v[1][0]=v[1][1]=1,v[0][1]=0;
        }
        Matrix operator *(const Matrix &m)const
        {
            Matrix c;
            for(int i=0;i<2;i++)
                for(int j=0;j<2;j++)
                {
                    c.v[i][j]=0;
                    for(int k=0;k<2;k++)
                        c.v[i][j]=(c.v[i][j]+v[i][k]*m.v[k][j])%mod;
                }
                return c;
        }
        void rev()
        {
            swap(v[0][0],v[1][1]);
            swap(v[0][1],v[1][0]);
        }
    };
    
    bool lz[maxn<<2];
    Matrix mul[maxn<<2];
    void PushUp(int u)//把当前结点的信息更新到父结点
    {
        mul[u] = mul[u<<1]*mul[u<<1|1];
    }
    void PushDown(int u)//把当前结点的信息更新给儿子结点
    {
        if (lz[u])
        {
            lz[u<<1] ^= 1;
            lz[u<<1|1] ^= 1;
            mul[u<<1].rev();
            mul[u<<1|1].rev();
            lz[u] = 0;
        }
    }
    void build(int l,int r,int u)
    {
        lz[u] = 0;
        if (l == r)
        {
            mul[u].init(s[l]-'0');
            return ;
        }
        int m = (l + r) >> 1;
        build(L);
        build(R);
        PushUp(u);
    }
    void update(int l1,int r1,int l,int r,int u)
    {
        if (l1 <= l && r <= r1)
        {
            lz[u] ^= 1;
            mul[u].rev();
            return ;
        }
        PushDown(u);
        int m = (l + r) >> 1;
        if (l1 <= m)
            update(l1 , r1 , L);
        if (m < r1)
            update(l1 , r1 , R);
        PushUp(u);
    }
    
    Matrix query(int l1,int r1,int l,int r,int u)
    {
        if (l1 <= l && r <= r1)
        {
            return mul[u];
        }
        PushDown(u);
        int m = (l + r) >> 1;
        Matrix res;
        res.v[0][0]=res.v[1][1]=1;
        res.v[0][1]=res.v[1][0]=0;
        if (l1<= m)
            res =res * query(l1 , r1 , L);
        if (m < r1)
            res = res * query(l1 , r1 , R);
        return res;
    }
    
    
    int main()
    {
        //freopen("input.txt","r",stdin);
        int T;scanf("%d",&T);
        while(T--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            scanf("%s",s+1);
            build(1,n,1);
            while(m--)
            {
                int k,l,r;
                scanf("%d%d%d",&k,&l,&r);
                if(k==1)update(l,r,1,n,1);
                else
                {
                   Matrix t= query(l,r,1,n,1);
                   LL ans=t.v[0][0]+t.v[0][1]+t.v[1][0]+t.v[1][1]-2;
                   printf("%lld
    ",(ans+mod)%mod);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    在Java和.Net中的MD5的一致性
    为Asp.net 网站新增发送手机短信功能
    ASP.NET如何防止页面重复提交
    转:Ajax调用Webservice和后台方法
    Ext 常用方法之一
    C#编程实战之类功能缺失
    Silverlight常用控件最佳实践之1.自定义TabControl禁用状态
    Blend4精选案例图解教程(五):可视数据管理
    DEDE织梦自定表单提交后自动发送邮件并到站长邮箱
    php常用数组相关处理函数(1)
  • 原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7420335.html
Copyright © 2011-2022 走看看