您的位置:首页 > 产品设计 > UI/UE

HDU 6155 Subsequence Count 线段树维护矩阵

2017-08-21 17:15 274 查看

Subsequence Count

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)


[align=left][b]Problem Description[/b][/align]
Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q 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 l and r (inclusive).
2. Counting the number of distinct subsequences in the substring S[l,...,r].

[align=left][b]Input[/b][/align]
The first line contains an integer T, denoting the number of the test cases.

For each test, the first line contains two integers N and Q.

The second line contains the string S.

Then Q lines follow, each with three integers type, l and r, denoting the queries.

1≤T≤5

1≤N,Q≤105

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

type∈{1,2}

1≤l≤r≤N

[align=left][b]Output[/b][/align]
For each query of type 2, output the answer mod (109+7) in one line.

[align=left][b]Sample Input[/b][/align]

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

[align=left][b]Sample Output[/b][/align]

11
6
8
10

[b]题解:[/b]
  设定dp[i][0/1] 到第i个字符以0/1结尾的子序列方案
  若s[i] = =1 : dp[i][1] = dp[i-1][0] + dp[i-1][1] + 1;
        dp[i][0] = dp[i-1][0];
若是s[i] == 0: dp[i][0] = dp[i-1][0] + dp[i-1][1] + 1;
        dp[i][1] = dp[i-1][1];
  写成矩阵,用线段树维护一段连续矩阵乘积,有点卡常数

#include<bits/stdc++.h>
using namespace std;
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N=5e5+20,M=1e6+10,inf=2147483647;

inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

const LL mod = 1e9+7;
char s
;

struct Matix {
LL arr[3][3];
}E,F,again,EE;
inline Matix mul(Matix a,Matix b) {
Matix ans;
memset(ans.arr,0,sizeof(ans.arr));
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 3; k++)
ans.arr[i][j] += a.arr[i][k] * b.arr[k][j],ans.arr[i][j] %= mod;
}
}
return ans;
}

Matix v[N * 4],now,facE
,facF
;
int lazy[N * 4],fi[N * 4],se[N * 4];

void change(int i) {
swap(v[i].arr[0][0],v[i].arr[1][0]);
swap(v[i].arr[0][1],v[i].arr[1][1]);
swap(v[i].arr[0][2],v[i].arr[1][2]);
swap(v[i].arr[0][0],v[i].arr[0][1]);
swap(v[i].arr[1][0],v[i].arr[1][1]);
swap(v[i].arr[2][0],v[i].arr[2][1]);
}
void push_down(int i,int ll,int rr) {
if(!lazy[i]) return;
lazy[ls] ^= 1;
lazy[rs] ^= 1;
change(ls);change(rs);
lazy[i] ^= 1;
}
inline void push_up(int i,int ll,int rr) {
v[i] = mul(v[ls],v[rs]);
}
void build(int i,int ll,int rr) {
lazy[i] = 0;
if(ll == rr) {
if(s[ll] == '1') v[i] = E,fi[i] = 1,se[i] = 0;
else v[i] = F,fi[i] = 0,se[i] = 1;
return ;
}
build(ls,ll,mid);
build(rs,mid+1,rr);
push_up(i,ll,rr);
}
inline void update(int i,int ll,int rr,int x,int y) {
push_down(i,ll,rr);
if(ll == x && rr == y) {
lazy[i] ^= 1;
change(i);
return ;
}
if(y <= mid) update(ls,ll,mid,x,y);
else if(x > mid) update(rs,mid+1,rr,x,y);
else update(ls,ll,mid,x,mid),update(rs,mid+1,rr,mid+1,y);
push_up(i,ll,rr);
}
inline Matix ask(int i,int ll,int rr,int x,int y) {
push_down(i,ll,rr);
if(ll == x && rr == y) {
return v[i];
}
if(y <= mid) return ask(ls,ll,mid,x,y);
else if(x > mid) return ask(rs,mid+1,rr,x,y);
else return mul(ask(ls,ll,mid,x,mid),ask(rs,mid+1,rr,mid+1,y));
push_up(i,ll,rr);
}

int main() {
EE.arr[0][0] = 1,EE.arr[1][1] = 1,EE.arr[2][2] = 1;

E.arr[0][0] = 1;E.arr[0][1] = 1;E.arr[0][2] = 1;
E.arr[1][1] = 1;E.arr[2][2] = 1;

F.arr[0][0] = 1;F.arr[1][0] = 1;F.arr[1][1] = 1;
F.arr[1][2] = 1;F.arr[2][2] = 1;

again.arr[0][2] = 1;

int T;
T = read();
while(T--) {
int n,Q;
n = read();
Q = read();
scanf("%s",s+1);
build(1,1,n);
while(Q--) {
int op,l,r;
op = read();
l = read();
r = read();
if(op == 1)
update(1,1,n,l,r);
else {
now = mul(again,ask(1,1,n,l,r));
printf("%lld\n",(now.arr[0][0]+now.arr[0][1])%mod);
}
}
}
return 0;
}


先考虑怎么算
s_1, s_2, \ldots, s_ns​1​​,s​2​​,…,s​n​​
的答案。设
dp(i, 0/1)dp(i,0/1)
表示考虑到
s_is​i​​
,以
0/10/1
结尾的串的数量。那么
dp(i, 0) =dp(i - 1, 0) + dp(i - 1, 1) + 1dp(i,0)=dp(i−1,0)+dp(i−1,1)+1
.
11
也同理。
那么假设在某个区间之前,
dp(i, 0/1) = (x, y)dp(i,0/1)=(x,y)
的话,过了这段区间,就会变成
(ax + by + c, dx + ey + f)(ax+by+c,dx+ey+f)
的形式,只要用线段树维护这个线性变化就好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: