链接: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;
}