zoukankan      html  css  js  c++  java
  • 洛谷 [T21776] 子序列

    题目描述

    你有一个长度为 (n) 的数列 ({a_n}) ,这个数列由 (0,1) 组成,进行 (m) 个的操作:

    (1 l r) :把数列区间$ [l,r]$ 内的所有数取反。即 (0) 变成 (1)(1) 变成 (0)

    (2 l r) :询问数列在区间 ([l, r]) 内共有多少个本质不同的子序列。

    输入输出格式

    输入格式:

    第一行包含两个整数 (n,m),意义如上所述。

    接下来一行包含 (n) 个数,表示数列 ({a_n})

    接下来 (m) 行,每行包含三个数,表示一个操作,操作格式如上所述。

    输出格式:

    对于每个询问,输出答案模 (10^{9}+7) 的结果。

    思路

    前置技能:

    维护一个长度为 (n)(3*3)(0/1) 矩阵序列

    1. 交换区间 ([l,r]) 中所有矩阵的第一行和第二行

    2. 查询区间 ([l,r]) 中所有矩阵从左到右乘起来的结果

    对于能快速合并的信息我们都可以用线段树来维护

    比如和,积,最值, 矩阵乘法, bitset, hash值,线性基

    还需要一个矩阵的结论:

    对于 3*3 的 0/1 矩阵来说 两矩阵的第一二行交换,他们的乘积的第一二行也交换

    所以可以对于交换的区间打 tag,用线段树维护

    本题思路

    考虑本质不同的子序列怎么求:

    设 f(i,0) 表示i号位置以前的以0结尾的本质不同的子序列数目

    设 f(i,1) 表示i号位置以前的以1结尾的本质不同的子序列数目

    转移方程 :

    如果 i 号位置是 0 ,(f(i,0) = f(i-1,0) + f(i-1,1) + 1 ; f(i, 1) = f(i-1, 1))

    如果 i 号位置是 1 ,(f(i,1) = f(i-1,0) + f(i-1,1) + 1 ; f(i, 0) = f(i-1, 0))

    用矩阵加速,可得:

    Alt text

    观察矩阵可得,对区间内序列取反,可以转化为把矩阵的前两行,前两列交换

    可用线段树来维护

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long 
    #define lson l, mid, rt<<1
    #define rson mid+1, r, rt<<1|1
    using namespace std;
    const int MOD = 1e9 + 7;
    int init() {
    	int rv = 0, fh = 1;
    	char c = getchar();
    	while(c <'0' || c > '9') {
    		if(c == '-') fh = -1;
    		c=getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		rv=(rv<<1) + (rv<<3) + c- '0';
    		c = getchar();
    	}
    	return fh * rv;
    }
    const int MAXN=100005;
    struct Matrix{
    	ll num[3][3];
    	int col;
    	Matrix() {
    		col = 0;
    		memset(num,0,sizeof(num));
    	}
    	void build(bool f){
    		col=3;
    		if(f) {
    			num[0][0] = num[0][1] = num[1][1] = num[2][1] = num[2][2] = 1;
    		}else {
    			num[0][0] = num[1][0] = num[2][0] = num[1][1] = num[2][2] = 1;
    		}
    	}
    	Matrix operator * (const Matrix &a) {
    		Matrix ans;
    		ans.col = col;
    		for(int i = 0 ; i < col ; i++) {
    			for(int j = 0 ; j < 3 ; j++) {
    				for(int k = 0 ; k < 3 ; k++) {
    					(ans.num[i][j] += num[i][k] * a.num[k][j]) %= MOD;
    				}
    			}
    		}
    		return ans;
    	}
    	void reserve() {
    		for(int i = 0 ; i < 3 ; i++) {
    			swap(num[0][i],num[1][i]);
    		}
    		for(int i = 0 ; i <3 ; i++) {
    			swap(num[i][0], num[i][1]);
    		}
    	}
    	void print() {
    		for(int i = 0 ; i<=col ;i++) {
    			for(int j = 0 ; j < 3 ; j++) {
    				printf("%d ",num[i][j]);
    			}
    			cout<<endl;
    		}
    	}
    };
    struct SGT{
    	Matrix sum[MAXN<<2];
    	bool tag[MAXN<<2];
    	void PushUp(int rt) {
    		sum[rt] = sum[rt<<1] * sum[rt<<1|1];
    	}
    	void build(int l, int r,int rt) {
    		if(l==r) {
    			bool f=init();
    			sum[rt].build(f);
    			return;
    		}
    		int mid = (l + r) >>1;
    		build(lson);
    		build(rson);
    		PushUp(rt);
    	}
    	void PushDown(int rt) {
    		if(tag[rt]) {
    			tag[rt<<1] = !tag[rt<<1] ;
    			tag[rt<<1|1] = !tag[rt<<1|1];
    			sum[rt<<1].reserve();
    			sum[rt<<1|1].reserve();
    			tag[rt]=0;
    		}
    	}
    	void Update(int L, int R, int l, int r, int rt) {
    		if(L <= l && r <= R) {
    			tag[rt]=!tag[rt];
    			sum[rt].reserve();
    			return;
    		}
    		PushDown(rt);
    		int mid = (l + r) >>1;
    		if(L <= mid) Update(L, R, lson);
    		if(mid < R) Update(L, R, rson);
    		PushUp(rt);
    	}
    	Matrix Query(int L, int R, int l, int r, int rt) {
    		if(L <= l && r <= R) {
    			return sum[rt];
    		}
    		PushDown(rt);
    		int mid = (l + r) >>1;
    		Matrix ans;
    		ans.col = 3;
    		ans.num[0][0] = ans.num[1][1] = ans.num[2][2] = 1;//ans.print();
    		if(L <= mid) ans = ans * Query(L, R, lson);
    		if(mid < R) ans = ans * Query(L, R, rson);
    		PushUp(rt);
    		return ans;
    	}
    }sgt;
    int n,m;
    int main() {
    	freopen("in.txt", "r", stdin);
    	n=init();m=init();
    	sgt.build(1,n,1);
    	for(int i = 1 ; i <= m ; i++) {
    		int t = init(), l = init(), r = init();
    		if(t == 1) {
    			sgt.Update(l, r, 1, n, 1);
    		}else {
    			Matrix ans;
    			ans.col = 1;ans.num[0][2] = 1;
    			ans = ans * sgt.Query(l, r, 1, n, 1);
    			//sgt.Query(l, r, 1, n, 1).print(); 
    			printf("%lld
    ",(ans.num[0][0] + ans.num[0][1])%MOD);
    		}
    	}
    	fclose(stdin);
    	return 0;
    }
    
  • 相关阅读:
    log4j2RCE复现
    Kernel panic: VFS: Unable to mount root fs on 08:08 解决方法
    关于QEMU/KVM中无法开启eth0网卡解决方法
    20212022年寒假学习进度04
    20212022年寒假学习进度05
    每日学习
    课程总结和加分项
    每日学习
    20212022年寒假学习进度03
    20212022年寒假学习进度01
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8447489.html
Copyright © 2011-2022 走看看