hdu 6155(線段樹+dp+矩陣)

Given a binary string S[1,…,N]S[1,…,N] (i.e. a sequence of 0’s and 1’s), and QQ 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 ll and rr (inclusive).
  2. Counting the number of distinct subsequences in the substring S[l,…,r]S[l,…,r].
    Input
    The first line contains an integer TT, denoting the number of the test cases.

For each test, the first line contains two integers NN and QQ.

The second line contains the string SS.

Then QQ lines follow, each with three integers typetype, ll and rr, denoting the queries.

1≤T≤51≤T≤5

1≤N,Q≤1051≤N,Q≤105

S[i]∈{0,1},∀1≤i≤NS[i]∈{0,1},∀1≤i≤N

type∈{1,2}type∈{1,2}

1≤l≤r≤N1≤l≤r≤N
Output
For each query of type 2, output the answer mod (109+7109+7) in one line.
Sample Input
2
4 4
1010
2 1 4
2 2 4
1 2 3
2 1 4
4 4
0000
1 1 2
1 2 3
1 3 4
2 1 4
Sample Output
11
6
8
10

題意是給一個01字符串,然後有2種操作,
1、把l到r這個區間的字符翻轉,
2、查詢l到r這個區間有多少個不同的子序列,(注意是子序列,可不連續),對1e9+7取模

先考慮dp求01串的不同子序列的個數。

對於操作2 可以得到 dp方程
如果s[i]==0 dp[i][0]=dp[i-1][1]+dp[i-1][0]+1;
不同的子序列個數就是i-1位置 是1或者0結尾的所有的串加上這一位,那麼所有的串至少長度爲2,再加上它自身,那麼長度爲1的只有它自身

所以當 s[i]==0 dp[i][0]=dp[i-1][1]+dp[i-1][0]+1;
dp[i][1]=dp[i-1][1];

s[i]=1 dp[i][1]=dp[i-1][1]+dp[i-1][0]+1;
dp[i][0]=dp[i-1][0];

得到矩陣 這裏寫圖片描述

那麼關於序列翻轉,就是相當於矩陣翻轉,把A矩陣變成B矩陣就好,把序列翻轉的結果,就是如果這是1矩陣 那麼被矩陣相乘 要有0矩陣的效果,就是中間列和第一列互換,同時dp[i][0]和dp[i][1]結果互換。。加上翻轉標記就好

#include <bits/stdc++.h>
using namespace std;
const int SIZE = 3;
const int N = 1e5+100;
const int mod = 1e9+7;
typedef long long ll;
struct Matrix
{
    ll m[SIZE][SIZE];
    friend Matrix operator* (const Matrix& a, const Matrix& b)
    {
        Matrix c;
        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
            {
                c.m[i][j] = 0;
                for (int k = 0; k < SIZE; k++)
                    c.m[i][j] += a.m[i][k] * b.m[k][j] % mod;
                c.m[i][j] %= mod;
            }
        return c;
    }
};

int filp[N*4],a[N];
Matrix sum[N*4];

Matrix s[2]={{1,0,0,1,1,0,1,0,1},{1,1,0,0,1,0,0,1,1}};

void out(int rt)
{
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        cout<<sum[rt].m[i][j]<<" ";
        cout<<endl;
    }
}

void build(int l,int r,int rt)
{
    filp[rt]=0;
    if(l==r)
    {
        sum[rt]=s[a[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    sum[rt]=sum[rt<<1]*sum[rt<<1|1];
    // cout<<(rt<<1)<<endl;
    // out(rt<<1);
    // cout<<(rt<<1|1)<<endl;
    // out(rt<<1|1);
    // cout<<rt<<endl;
    // out(rt);
}

void huan(int rt)
{
    swap(sum[rt].m[0][0],sum[rt].m[0][1]);
    swap(sum[rt].m[1][0],sum[rt].m[1][1]);
    swap(sum[rt].m[2][0],sum[rt].m[2][1]);
    swap(sum[rt].m[0][0],sum[rt].m[1][0]);
    swap(sum[rt].m[0][1],sum[rt].m[1][1]);
}


void pushdown(int rt)
{
    if(filp[rt])
    {
        huan(rt<<1);
        huan(rt<<1|1);
        filp[rt<<1]^=1;
        filp[rt<<1|1]^=1;
        filp[rt]=0;
    }
}


void update(int l,int r,int L,int R,int rt)
{
    if(L<=l&&R>=r)
    {
        huan(rt);
        filp[rt]^=1;
        return ;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid) update(l,mid,L,R,rt<<1);
    if(R>mid) update(mid+1,r,L,R,rt<<1|1);
    sum[rt]=sum[rt<<1]*sum[rt<<1|1];
}

Matrix query(int l,int r,int L,int R,int rt)
{
    if(L<=l&&R>=r)
    {
        return sum[rt];
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    Matrix res={1,0,0,0,1,0,0,0,1};
    if(L<=mid) res=res*query(l,mid,L,R,rt<<1);
    if(R>mid) res=res*query(mid+1,r,L,R,rt<<1|1);
    sum[rt]=sum[rt<<1]*sum[rt<<1|1];
    return res;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%1d",&a[i]);
        build(1,n,1);
        while(m--)
        {
            int op,L,R;
            scanf("%d%d%d",&op,&L,&R);
            if(op==2){
                Matrix ans=query(1,n,L,R,1);
                Matrix hh={0,0,1,0,0,0,0,0,0};
                hh=hh*ans;
                printf("%lld\n",(hh.m[0][0]+hh.m[0][1] )%mod);
            }
            else if(op==1)
                update(1,n,L,R,1);
        }
    }
}
發佈了60 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章