Subsequence Count

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155
思路:
考虑构造dp
dp[i][j]表示前i个,以j为结尾的不同子序列有多少个。
如果第i个是1,那么
dp[i][1]=dp[i-1][1]+dp[i-1][0]+1,
dp[i][0]=dp[i-1][0]
如果第i个是0,那么
dp[i][1]=dp[i-1][1]
dp[i][0]=dp[i-1][1]+dp[i-1][0]
怎么去想?第i个为1,就把前面i-1个得到的序列都在末尾加上s[i],那么会导致,没有1这个单独的序列了,(原来的1变为了1,1)那么+1即补上。
这是一个递推式子,那么我们自然可以写出转移矩阵

第i个是1:
1 0 0 
1 1 0 
1 0 1
第i个是0:
1 1 0
0 1 0
0 1 1         

然后关于修改查询用线段树优化,维护矩阵
但你可能会问flip不是对矩阵的操作吗?那怎么区间修改呢。很容易验证,就这道题来讲,由于两个矩阵之间相差的是1,2行做一次初等行变换,1,2列做一次初等列变换,如果对一个区间做flip操作,只需要对这个区间之前得到的结果矩阵,做同样的初等行列变换即可。
证:设初等矩阵为p1,2。对矩阵做初等行变换就是左乘初等矩阵,对矩阵做初等列变换就是右乘初等矩阵,如果原来矩阵乘法中,有BA/AB,那么其中间的初等矩阵在做了flip操作后也不会消失,如果是AA/BB,那么其中间的初等矩阵由于会消掉,因此也不会发生改变,所以结论就是矩阵与矩阵间不会产生新的矩阵,flip后只会在两端同乘初等矩阵,此结论仅限于本题,其他题可以类似的去考虑。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int maxn = 1e5+7;
const int mod = 1e9+7;
const int mSize = 3;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}

struct Matrix
{
    long long v[mSize][mSize];
    friend Matrix operator* (const Matrix& a, const Matrix& b)
    {
        Matrix c;
        for (int i = 0; i < mSize; i++)
            for (int j = 0; j < mSize; j++)
            {
                c.v[i][j] = 0;
                for (int k = 0; k < mSize; k++)
                    c.v[i][j] += a.v[i][k] * b.v[k][j] % mod;
                c.v[i][j] %= mod;
            }
        return c;
    }
};

const Matrix m[2] = {{1, 0, 0, 1, 1, 0, 1, 0, 1},{1, 1, 0, 0, 1, 0, 0, 1, 1}};

char s[maxn];
Matrix data[maxn<<2];
bool flip[maxn<<2];



inline void mat_build(int o, int l, int r)
{
    if(l == r)
        data[o] = m[s[l] - '0'];
    else{
        int mid = (l + r) >> 1;
        mat_build(o << 1 , l, mid);
        mat_build(o << 1 | 1, mid+1, r);
        data[o] = data[o << 1]*data[o << 1 | 1];
    }
    flip[o] = 0;
}


inline void doFlip(Matrix& mat)
{
    swap(mat.v[0][0], mat.v[0][1]);
    swap(mat.v[1][0], mat.v[1][1]);
    swap(mat.v[2][0], mat.v[2][1]);    
    swap(mat.v[0][0], mat.v[1][0]);
    swap(mat.v[0][1], mat.v[1][1]);
    swap(mat.v[0][2], mat.v[1][2]);
}


inline void pushdown(int o)
{
    if(flip[o])
    {
        flip[o << 1] ^= flip[o];
        flip[o << 1 | 1] ^= flip[o];
        doFlip(data[o << 1]);
        doFlip(data[o << 1 | 1]);
        flip[o] = 0;
    }
}

inline void mat_flip(int o, int l, int r, int ql, int qr)
{
    if(ql <= l && r <= qr)
    {
        flip[o] ^= 1;
        doFlip(data[o]);
        return ;
    }
    if(qr < l || ql > r)
    {
        return ;
    }
    int mid = (r + l) >> 1;
    pushdown(o);
    mat_flip(o << 1, l, mid, ql, qr);
    mat_flip(o << 1 | 1, mid+1, r, ql, qr);
    data[o] = data[o << 1]*data[o << 1 | 1];
}


inline Matrix mat_query(int o, int l, int r, int ql, int qr)
{    
    if(ql <= l && r <= qr)
    {
        return data[o];
    }
    if(qr < l || ql > r)
    {
        return {1, 0, 0, 0, 1, 0, 0, 0, 1};
    }
    int mid = (r + l) >> 1;
    pushdown(o);
    return mat_query(o << 1, l, mid, ql, qr) * mat_query(o << 1 | 1, mid+1, r, ql, qr);
}

signed main()
{
    int t;
    scanf("%lld",&t);
    while(t--)
    {
        int n, q;
        scanf("%lld%lld",&n,&q);
        scanf("%s", s + 1);
        mat_build(1, 1, n);
        while(q--)
        {
            int op, l, r;
            scanf("%lld%lld%lld",&op,&l,&r);
            if(op == 1){
                mat_flip(1, 1, n, l, r);
            }
            else{
                Matrix mat = mat_query(1, 1, n, l, r);
                printf("%lld\n",(mat.v[2][0]+mat.v[2][1])%mod);
            }
        }
    }
    return 0;
}
全部评论

相关推荐

评论
3
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
7319次浏览 66人参与
# 你的实习产出是真实的还是包装的? #
1411次浏览 35人参与
# 巨人网络春招 #
11247次浏览 223人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7192次浏览 38人参与
# 简历第一个项目做什么 #
31397次浏览 317人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
186626次浏览 1116人参与
# 米连集团26产品管培生项目 #
5101次浏览 207人参与
# 研究所笔面经互助 #
118808次浏览 577人参与
# 面试紧张时你会有什么表现? #
30431次浏览 188人参与
# 简历中的项目经历要怎么写? #
309720次浏览 4171人参与
# AI时代,哪些岗位最容易被淘汰 #
62951次浏览 760人参与
# 职能管理面试记录 #
10753次浏览 59人参与
# 网易游戏笔试 #
6397次浏览 83人参与
# 腾讯音乐求职进展汇总 #
160480次浏览 1107人参与
# 把自己当AI,现在最消耗你token的问题是什么? #
7059次浏览 155人参与
# 正在春招的你,也参与了去年秋招吗? #
362921次浏览 2635人参与
# 你怎么看待AI面试 #
179558次浏览 1193人参与
# 小红书求职进展汇总 #
226969次浏览 1357人参与
# 你觉得通信/硬件有必要实习吗? #
155407次浏览 1065人参与
# 从哪些方向判断这个offer值不值得去? #
56717次浏览 357人参与
# 校招笔试 #
468444次浏览 2959人参与
# 你的房租占工资的比例是多少? #
92166次浏览 896人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务