HDU6155 Subsequence Count
Subsequence Count
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 933 Accepted Submission(s): 329
Problem Description
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:
- Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).
- Counting the number of distinct subsequences in the substring S[l,...,r].
Input
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
Output
For each query of type 2, output the answer mod (109+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
Source
2017中国大学生程序设计竞赛 - 网络选拔赛
题解
看到此题直接想怎么用数据结构维护。。。就GG了。。
发现可以DP,看看能不能矩阵快速幂,然后拿数据结构维护矩阵乘法
dp[i][0]表示从开始(标记为1)到i,以0位结尾的本质不同的子序列个数
dp[i][1]表示从开始(标记为1)到i,以1位结尾的本质不同的子序列个数
如果numi = 0 dp[i][0] = dp[i - 1][1] + dp[i - 1][0] + 1, dp[i][1] = dp[i - 1][1]
矩阵
dp[i][0] dp[i][1] 1
1 0 0
1 1 0
1 0 1
如果numi = 1 dp[i][0] = dp[i - 1][0], dp[i][1] = dp[i - 1][0] + dp[i - 1][1] + 1
矩阵
dp[i][0] dp[i][1] 1
1 1 0
0 1 0
0 1 1
矩阵乘法有结合律,拿线段树维护矩阵乘法就好了。
还可以用线段树维护0/1个数,倍增求答案矩阵(矩阵ksm)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int MAXN = 200000 + 10;
struct Matrix
{
long long data[3][3];
Matrix(){memset(data, 0, sizeof(data));}
friend Matrix operator*(const Matrix &a, const Matrix &b)
{
Matrix ans;
for(int k = 0;k < 3;++ k)
for(int i = 0;i < 3;++ i)
for(int j = 0;j < 3;++ j)
ans.data[i][j] += a.data[i][k] * b.data[k][j], ans.data[i][j] %= MOD;
return ans;
}
};
struct Node
{
int l, r, lazy;
Matrix data;
Node(){l = r = -1, lazy = 0;}
}node[MAXN << 2];
inline void change(Node &x)
{
swap(x.data.data[0][0], x.data.data[1][1]);
swap(x.data.data[0][1], x.data.data[1][0]);
swap(x.data.data[0][2], x.data.data[1][2]);
swap(x.data.data[2][0], x.data.data[2][1]);
}
void pushdown(int &o)
{
if(!node[o].lazy) return;
node[o].lazy = 0;
change(node[o << 1]), node[o << 1].lazy ^= 1;
change(node[o << 1 | 1]), node[o << 1 | 1].lazy ^= 1;
}
Node merge(Node &a, Node &b)
{
if(a.l == -1) return b;
if(b.l == -1) return a;
Node re;
re.l = a.l, re.r = b.r;
re.data = a.data * b.data;
return re;
}
int num[MAXN], t, n, q;
char s[MAXN];
Matrix dp0, dp1;
void build(int o = 1, int l = 1, int r = n)
{
if(l == r)
{
node[o].l = l, node[o].r = r, node[o].lazy = 0;
if(num[l]) node[o].data = dp1;
else node[o].data = dp0;
return;
}
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
node[o] = merge(node[o << 1], node[o << 1 | 1]);
return;
}
void modify(int ll, int rr, int o = 1)
{
pushdown(o);
if(ll <= node[o].l && rr >= node[o].r)
{
change(node[o]), node[o].lazy ^= 1;
return;
}
int mid = (node[o].l + node[o].r) >> 1;
if(mid >= ll) modify(ll, rr, o << 1);
if(mid < rr) modify(ll, rr, o << 1 | 1);
node[o] = merge(node[o << 1], node[o << 1 | 1]);
return;
}
Node ask(int ll, int rr, int o = 1)
{
pushdown(o);
if(ll <= node[o].l && rr >= node[o].r) return node[o];
int mid = (node[o].l + node[o].r) >> 1;
Node a,b;
if(mid >= ll) a = ask(ll, rr, o << 1);
if(mid < rr) b = ask(ll, rr, o << 1 | 1);
Node re = merge(a, b);
return re;
}
int main()
{
read(t);
dp0.data[0][0] = dp0.data[1][0] = dp0.data[1][1] = dp0.data[2][0] = dp0.data[2][2] = 1;
dp1.data[0][0] = dp1.data[0][1] = dp1.data[1][1] = dp1.data[2][1] = dp1.data[2][2] = 1;
for(;t;--t)
{
read(n), read(q);
scanf("%s", s + 1);
for(int i = 1;i <= n;++ i) num[i] = s[i] - '0';
build();
for(int i = 1;i <= q;++ i)
{
int tmp1,tmp2,tmp3;
read(tmp1), read(tmp2), read(tmp3);
if(tmp1 == 1) modify(tmp2, tmp3);
else
{
Node tmp = ask(tmp2, tmp3);
printf("%lld\n", (tmp.data.data[2][0] + tmp.data.data[2][1]) % MOD);
}
}
}
return 0;
}