您的位置:首页 > 其它

HDU6155(dp + 线段树区间更新 + 矩阵性质)

2017-08-20 20:23 211 查看


Subsequence Count

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

Total Submission(s): 304    Accepted Submission(s): 126


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:

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].

 

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
题意:给你一个01串,两种操作,一种查询操作,查询l, r中有多少不同的子串(不一定要连续),第二种时修改操作,把区间l, r中的0,1翻转,0变成1, 1变成0.
解题思路:先考虑一个问题,给你一个串我们怎样求这个串的子串的个数。我们容易想到用dp。dp[i][0]表示考虑到第i位以0结尾的子串个数,dp[i][1]表示考虑到第i位以1结尾的子串的个数,则易得以下状态转移方程: 当s[i] = '0'时dp[i][0] = dp[i - 1][0] + dp[i - 1][1] + 1;dp[i][1] = dp[i - 1][1];当s[i] = '1'时dp[i][0] = dp[i - 1][0];dp[i][1] = dp[i - 1][0] + dp[i - 1][1] + 1;然后我们可以写出递推式的系数矩阵:当s[i] = '0'时dp[i][0] 1 1 1 dp[i - 1][0]dp[i][1] = 0 1 0 * dp[i - 1][1]1 0 0 1 1当s[i] = '1'dp[i][0] 1 1 1 dp[i - 1][0]dp[i][1] = 0 1 0 * dp[i - 1][1]1 0 0 1 1然后我们用线段树维护区间矩阵乘积就行。当遇到修改操作时,我们可以发现0变成1,1变成0,对应的区间矩阵结果就变成然后的矩阵第一列和第二列交换,然后第一行和第二行交换后的矩阵,自己可以用手演算一下,这是个规律(不知道那些大佬是怎样看出来的)。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long LL;
const LL mod = 1e9 + 7;
int n, q;
char s[maxn];
struct Matrix{
LL v[3][3];
Matrix operator *(const Matrix &res){
Matrix ans;
for(int i = 0; i <= 2; i++)
{
for(int j = 0; j <= 2; j++)
{
ans.v[i][j] = 0;
for(int k = 0; k <= 2; k++)
{
ans.v[i][j] += (v[i][k] * res.v[k][j]) % mod;
ans.v[i][j] %= mod;
}
}
}
return ans;
}
void rev(){//矩阵第一列与第二列交换,然后第一行与第二行交换
swap(v[0][0], v[1][1]);
swap(v[1][0], v[0][1]);
swap(v[0][2], v[1][2]);
}

};
Matrix x1 = {1, 1, 1, 0, 1, 0, 0, 0, 1};//s[i]为0时的递推矩阵
Matrix x2 = {1, 0, 0, 1, 1, 1, 0, 0, 1};//s[i]为1时的递推矩阵
Matrix s1 = {1, 0, 0, 0, 0, 0, 1, 0, 0};//s[i]为0时的初始矩阵
Matrix s2 = {0, 0, 0, 1, 0, 0, 1, 0, 0};//s[i]为0时的初始矩阵
struct node{
int l, r;
Matrix sum;//区间矩阵乘积
int add;//是否翻转,0表示不翻转,1表示翻转
}Node[maxn<<2];
void pushUp(int i)
{
int lson = i<<1;
int rson = lson|1;
Node[i].sum = Node[rson].sum * Node[lson].sum;
}
void pushDown(int i)
{
int lson = i<<1;
int rson = lson|1;
Node[lson].add ^= 1;
Node[rson].add ^= 1;
Node[lson].sum.rev();
Node[rson].sum.rev();
Node[i].add = 0;
}
void build(int i, int l, int r)
{
Node[i].l = l;
Node[i].r = r;
Node[i].add = 0;
if(l == r)
{
if(s[l] == '0') Node[i].sum = x1;
else Node[i].sum = x2;
return;
}
int f = i;
i <<= 1;
int mid = (l + r)>>1;
build(i, l, mid);
build(i|1, mid + 1, r);
pushUp(f);
}
void update(int i, int l, int r)
{
if(Node[i].l == l && Node[i].r == r)
{
Node[i].add ^= 1;
Node[i].sum.rev();
return;
}
if(Node[i].add) pushDown(i);
int f = i;
i <<= 1;
if(r <= Node[i].r) update(i, l, r);
else if(l >= Node[i|1].l) update(i|1, l, r);
else
{
update(i, l, Node[i].r);
update(i|1, Node[i|1].l, r);
}
pushUp(f);
}
Matrix queryMatrix(int i, int l, int r)
{
if(Node[i].l == l && Node[i].r == r)
{
return Node[i].sum;
}
if(Node[i].add) pushDown(i);
i <<= 1;
if(r <= Node[i].r) return queryMatrix(i, l, r);
else if(l >= Node[i|1].l) return queryMatrix(i|1, l, r);
else
{
Matrix t1 = queryMatrix(i, l, Node[i].r);
Matrix t2 = queryMatrix(i|1, Node[i|1].l, r);
return t2 * t1;
}
}
int queryId(int i, int loc)
{
if(Node[i].l == Node[i].r)
{
return Node[i].add;
}
if(Node[i].add) pushDown(i);
i <<= 1;
if(loc <= Node[i].r) return queryId(i, loc);
else if(loc >= Node[i|1].l) return queryId(i|1, loc);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
build(1, 1, n);
int op, l, r;
for(int i = 1; i <= q; i++)
{
scanf("%d%d%d", &op, &l, &r);
if(op == 1)
{
update(1, l, r);
}
else
{
if(l == r)
{
printf("1\n");
continue;
}
int id = queryId(1, l);
Matrix re = queryMatrix(1, l + 1, r);
Matrix term;
if(id == 0)
{
if(s[l] == '0') term = s1;
else term = s2;
}
else
{
if(s[l] == '0') term = s2;
else term = s1;
}
term = re * term;
LL cnt = (term.v[0][0] + term.v[1][0]) % mod;
printf("%lld\n", cnt);
}
}
}
return 0;
}


Source

2017中国大学生程序设计竞赛
- 网络选拔赛
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐