HDU 6155 Subsequence Count(线段树 dp)
2017-08-20 15:11
489 查看
/** HDU 6155 Subsequence Count 题意:一个长度为n的二进制串,q个查询,两种操作: 1 l r 将在区间[l, r]的二进制串取反 2 l r 查询区间[l, r]的不同子序列的个数 思路:首先看整个区间[1, n]子序列的情况,dp[i][1]表示到i这个位置的时候以1结尾的子序列的个数, dp[i][0]表示到i这个位置的时候以0结尾的子序列的个数,那么有如下转移方程: 1、 如果第i+1个位置是1,那么dp[i+1][1] = dp[i][1]+dp[i][0]+1, dp[i+1][0] = dp[i][0] 2、 如果第i+1个位置是0,那么dp[i+1][0] = dp[i][1]+dp[i][0]+1, dp[i+1][1] = dp[i][1] 根据转移方程得出递推矩阵 第一种情况: dp[i+1][1] 1 1 1 dp[i][1] dp[i+1][0] = 0 1 0 * dp[i][0] 1 0 0 1 1 第二种情况 dp[i+1][1] 1 0 0 dp[i][1] dp[i+1][0] = 1 1 1 * dp[i][0] 1 0 0 1 1 这个不需要快速幂,只需要求出之前的每一个矩阵就能得出这个区间的最终矩阵和第一个位置的关系 所以同样,对于区间[l, r]也可以这样做,即求出整个区间的最终矩阵 对于1操作用线段树去更新, 对于合并区间维护的时候,比如[l,mid]和[mid+1,r]合并成[l,r]的时候, 因为矩阵具有结合律,需要用[mid+1, r]的矩阵去乘以[l, mid]的矩阵,这样得出的就是,区间[l,r] 的矩阵, 这里要注意一定是[mid+1, r]的矩阵去乘以[l, mid]的矩阵,矩阵不具备交换律的性质, 还需要记录下线段树节点对应的区间翻转的时候的矩阵, 合并也差不多,就是把右左孩子对应区间翻转 的矩阵乘起来 查询的时候,要先遍历左孩子(左边的区间),用ans1 和ans2分别表示查询到区间[l, x]的时候已经搜索 到的以1结尾和以0结尾的子序列个数,那么查询下一个区间[x+1, y] 的时候,ans1 和ans2的新值计算方法 就是用[x+1,y]的矩阵matrix去乘以他们, 如下所示(new_ans1, new_ans2分别代表ans1和ans2的新值): new_ans1 ans1 new_ans2 = matrix * ans2 1 1 还有个优化的问题,直接计算矩阵的话是3*3*3 = 27,总的时间就是O(27*T*q*log n),一个优化是发现 每个矩阵最后一行[0 0 1]的值是不变的,这里不去计算, 还有就是0乘以任何数为0,那个一定为0的跳过.. **/ #include<bits/stdc++.h> typedef long long ll; const ll mod = 1e9 + 7; const int maxn = 6e5 + 10; using namespace std; int T, kase = 1, n, q; int ql, qr, op; ll lazy[maxn]; char s[maxn]; const ll A[2][3][3] = {1,0,0,1,1,1,0,0,1, 1,1,1,0,1,0,0,0,1}; ///当前位是0和1的递推矩阵 ll mat[maxn][2][3][3]; ll ans1, ans2; void init(int o, int t, const ll mt[3][3]) { for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { mat[o][t][i][j] = mt[i][j]; } } } void push_up(int o) { int o1 = o << 1, o2 = o << 1 | 1; int t1 = lazy[o1], t2 = lazy[o2]; int n1 = t1 ^ 1, n2 = t2 ^ 1; for(int i = 0; i < 2; i++) { for(int j = 0; j < 3; j++) { ll c = 0; for(int k = 0; k < 2; k++) { c = (c + mat[o2][t2][i][k] * mat[o1][t1][k][j]) % m b595 od; ///注意要先是右儿子 } mat[o][0][i][j] = c; } mat[o][0][i][2] = (mat[o][0][i][2] + mat[o2][t2][i][2]) % mod; } for(int i = 0; i < 2; i++) { for(int j = 0; j < 3; j++) { ll c = 0; for(int k = 0; k < 2; k++) { c = (c + mat[o2][n2][i][k] * mat[o1][n1][k][j]) % mod; ///注意要先是右儿子 } mat[o][1][i][j] = c; } mat[o][1][i][2] = (mat[o][1][i][2] + mat[o2][n2][i][2]) % mod; } } void build(int o, int l, int r) { lazy[o] = 0; memset(mat[o], 0, sizeof mat[o]); mat[o][0][2][2] = mat[o][1][2][2] = 1; if(l == r) { int c = s[l] - '0'; init(o, 0, A[c]); init(o, 1, A[c ^ 1]); return ; } int mid = (l + r) >> 1; int o1 = o << 1, o2 = o << 1 | 1; build(o1, l, mid); build(o2, mid + 1, r); push_up(o); } void push_down(int o) { if(!lazy[o]) return ; int o1 = o << 1, o2 = o << 1 | 1; lazy[o1] ^= 1; lazy[o2] ^= 1; lazy[o] = 0; } void update(int o, int l, int r) { if(r < ql || l > qr) return ; if(l >= ql && r <= qr) { lazy[o] ^= 1; return ; } push_down(o); int mid = (l + r) >> 1; int o1 = o << 1, o2 = o << 1 | 1; update(o1, l, mid); update(o2, mid + 1, r); push_up(o); } void query(int o, int l, int r) { if(r < ql || l > qr) return ; if(l >= ql && r <= qr) { ll nx, ny, t = lazy[o]; nx = mat[o][t][0][0] * ans1 % mod; nx = (nx + mat[o][t][0][1] * ans2 + mat[o][t][0][2]) % mod; ny = mat[o][t][1][0] * ans1 % mod; ny = (ny + mat[o][t][1][1] * ans2 + mat[o][t][1][2]) % mod; ans1 = nx; ans2 = ny; return ; } push_down(o); int mid = (l + r) >> 1; int o1 = o << 1, o2 = o << 1 | 1; query(o1, l, mid); query(o2, mid + 1, r); push_up(o); } int input() { int res = 0, ch, flag = 0; if((ch = getchar()) == '-') flag = 1; ///正负 else if(ch >= '0' && ch <= '9') res = ch - '0'; while((ch = getchar()) >= '0' && ch <= '9' ) res = res * 10 + ch - '0'; return flag ? -res : res; } int main() { T = input(); while(T--) { n = input(); q = input(); scanf("%s", s); build(1, 0, n - 1); while(q--) { op = input(); ql = input(); qr = input(); ql--; qr--; if(op == 1) update(1, 0, n - 1); else { ans1 = ans2 = 0; query(1, 0, n - 1); printf("%lld\n", (ans1 + ans2) % mod); } } } return 0; }
相关文章推荐
- HDU 6155 Subsequence Count [线段树维护矩阵]
- HDU 6155 Subsequence Count 线段树维护矩阵
- hdu 6155 - Subsequence Count 线段树+dp+矩阵
- hdu 6155 - Subsequence Count
- 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6155 Subsequence Count 矩阵快速幂
- Hdu 6155 Subsequence Count 矩阵计算DP+线段树维护
- HDU 6155 Subsequence Count(dp+线段树)
- HDU 6155 Subsequence Count
- HDU Common Subsequence (dp)
- HDU 3336 Count the string (kmp+dp)
- (HDU)3336 - Count the string 【KMP】+【DP】
- HDU 1159——Common Subsequence(DP)
- Count the string - HDU 3336(next+dp)
- HDU 4588 Count The Carries 数位DP || 打表找规律
- hdu 1556 Color the ball 线段树,树状树组,与dp思想的树组解决技巧
- HDU 4117 GRE Words (AC自动机 + 线段树优化DP) 2011年成都现场赛G题
- HDU Palindrome subsequence(区间DP)
- hdu 1423 Greatest Common Increasing Subsequence 经典dp
- HDU 3336 Count the string ( KMP next函数的应用 + DP )
- 【HDU 3336】Count the string(KMP+DP)