洛谷T21776 子串行

2021-09-07 16:49:28 字數 3229 閱讀 1355

你有乙個長度為 nn 的數列 \ ,這個數列由 0,10,1 組成,進行 mm 個的操作:

1~l~r1lr :把數列區間 [l, r][l,r] 內的所有數取反。即 00 變成 11 ,11 變成 00 。

2~l~r2lr :詢問數列在區間 [l, r][l,r] 內共有多少個本質不同的子串行。

輸入格式:

第一行包含兩個整數 n, mn,m ,意義如上所述。

接下來一行包含 nn 個數,表示數列 \ 。

接下來 mm 行,每行包含三個數,表示乙個操作,操作格式如上所述。

輸出格式:

對於每個詢問,輸出答案模 10^9 + 7109+7 的結果。

輸入樣例#1: 

複製

4 4

1 0 1 0

2 1 4

2 2 4

1 2 3

2 1 4

輸出樣例#1: 

複製

11

68

對於 10 \%10% 的資料,1 \leq n, m \leq 10^21≤n,m≤102 。

對於 30 \%30% 的資料,1 \leq n, m \leq 10^31≤n,m≤103 。

對於 100 \%100% 的資料,1 \leq n, m \leq 10^51≤n,m≤105 。

這道題同hdu6155(只不過我在hdu上t飛了)

首先我們考慮一下暴力怎麼寫

dp[i][1]表示到第$i$個位置,以$1$結尾,本質不同的子串行

dp[i][0]表示到第$i$個位置,以$0$結尾,本質不同的子串行

轉移的時候,假設第$i$個字元是1

那麼對它有貢獻的是以前以$0$結尾的子串行,以及以前以$1$結尾的子串行,以及空串

那麼此時

$dp[i][1]=dp[i-1][0]+dp[i-1][1]+1$

$dp[i][0]=dp[i-1][0]$

當第$i$個字元是$0$的時候同理,不難得到

$dp[i][1]=dp[i-1][1]$

$dp[i][0]=dp[i-1][0]+dp[i-1][1]+1$

大家有沒有發現一件事情?

這個dp的轉移是遞推!也就是說我們可以用矩陣乘法來加速!

而矩陣乘法可以用線段樹來維護!

它的矩陣為

對於操作1的話,先交換要改變的矩陣的第一行和第二行,再交換要改變的矩陣的第一列和第二列

至於為什麼?這個可以轉移之間的關係入手,也可以直接找規律

這樣就實現了兩個矩陣的轉換

另外還有一點、

對於結果矩陣,我們只會用到[3][1]和[3][2]這兩項(分別代表dp[n][1],dp[n][0])

//

luogu-judger-enable-o2

//luogu-judger-enable-o2

#include#include

#include

#define ll long long int

#define ls k<<1

#define rs k<<1|1

using

namespace

std;

const

int maxn=1e6+10

;const

int mod=1e9+7

;inline

intread()

while(c>='

0'&&c<='9')

return x*f;

}char

c[maxn];

struct

matrix

};struct

node

t[maxn];

matrix zero,one,hhhhh;

matrix rev(matrix &a)

matrix matrixmul(matrix a,matrix b)

void update(int

k)void pushdown(intk)}

void build(int k,int ll,int

rr)

int mid=ll+rr>>1

; build(ls,ll,mid);

build(rs,mid+1

,rr);

update(k);

}void intervalchange(int k,int ll,int

rr) pushdown(k);

int mid=t[k].l+t[k].r>>1

;

if(ll<=mid) intervalchange(ls,ll,rr);

if(rr>mid) intervalchange(rs,ll,rr);

update(k);

}matrix intervalask(

int k,int ll,int

rr) pushdown(k);

ll mid=t[k].l+t[k].r>>1

;

if(ll<=mid)

ans=matrixmul(intervalask(ls,ll,rr),ans);

if(rr>mid)

ans=matrixmul(ans,intervalask(rs,ll,rr));

return

ans;

}int

main()

else

if(opt==2

)

}

}return0;

}

洛谷T21776 子串行

你有乙個長度為 nn 的數列 這個數列由 0,10,1 組成,進行 mm 個的操作 1 l r1lr 把數列區間 l,r l,r 內的所有數取反。即 00 變成 11 11 變成 00 2 l r2lr 詢問數列在區間 l,r l,r 內共有多少個本質不同的子串行。輸入格式 第一行包含兩個整數 n,...

洛谷 P1410 子串行

這題乍一看毫無思路。顯然不可能窮舉長度為n 2的嚴格遞增子串行。不過聯想到noip1999 普及組 的飛彈攔截的第二問,就有思路了。這題其實與它的第二問差不多,只要算出該序列的最大非公升子串行長度l,判斷一下是否大於2即可。1.假如l 2,顯然乙個嚴格遞增子串行至多包含非公升子串行的乙個元素,2個子...

洛谷 P1410 子串行

給定乙個長度為n n為偶數 的序列,問能否將其劃分為兩個長度為n 2的嚴格遞增子串行,輸入格式 若干行,每行表示一組資料。對於每組資料,首先輸入乙個整數n,表示序列的長度。之後n個整數表示這個序列。輸出格式 同輸入行數。對於每組資料,如果存在一種劃分,則輸出 yes 否則輸出 no 輸入樣例 1 6...