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中国大学生程序设计竞赛
- 网络选拔赛
相关文章推荐
- “盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛题解&&源码【A,水,B,水,C,水,D,快速幂,E,优先队列,F,暴力,G,贪心+排序,H,STL乱搞,I,尼姆博弈,J,差分dp,K,二分+排序,L,矩阵快速幂,M,线段树区间更新+Lazy思想,N,超级快速幂+扩展欧里几德,O,BFS】
- Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]
- nyoj 116 士兵杀敌(四)(线段树区间更新和单点查询)
- HDU5239 Doom(线段树,区间更新,区间平方)
- hdu 5239 区间平方 线段树区间更新
- 哈理工OJ 1566 Countless Candies【线段树】【区间更新、点查询】
- HDU 1166 敌兵布阵 (线段树单点更新 区间查询)
- POJ 3264 Balanced Lineup【简单线段树,区间最值,无更新】
- HDU 1698 Just a Hook 线段树区间更新(值进行覆盖)
- HDU 4819:单点更新,区间查询的二维线段树
- HDU 4027 Can you answer these queries? 线段树 区间更新(优化)
- HDU 3577 Fast Arrangement 线段树 区间更新
- hdu - 1689 Just a Hook (线段树区间更新)
- 线段树区间更新区间求和(转延迟标记精讲)
- POJ3468 区间更新+区间查询(线段树)
- poj2777 Count Color 线段树区间更新+位操作
- zoj 1610 Count the Colors 线段树 区间更新
- HDU 4027 Can you answer these queries?【线段树+区间更新】
- C - A Simple Problem with Integers ——线段树_区间更新
- HDU 5239 Doom 【打表找规律 + 线段树区间更新中的单点更新】好题!