首页 > 编程语言 >广州大学第十七届ACM大学生程序设计竞赛 L. 因子模仿 - hard version 线段树维护矩阵

广州大学第十七届ACM大学生程序设计竞赛 L. 因子模仿 - hard version 线段树维护矩阵

时间:2023-04-11 22:47:57浏览次数:57  
标签:广州大学 hard 矩阵 ACM a1 int a2 b1 b2

传送门

大致思路:

  观察发现,茉美香胜利会叠加对手所有状态,茉美香失败会被对手叠加所有状态。我们可以用矩阵[a1, a2, b1, b2]表示两个人的状态(其中a1, a2表示茉美香, b1, b2表示对手)茉美香赢了之后的状态是[a1 + b1, a2 + b2, b1, b2], 茉美香输了之后的状态是[a1, b1, a1 + b1, a2 + b2]。[a1, a2, b1, b2]乘上一个什么样的矩阵会变成[a1 + b1, a2 + b2, b1, b2],我们手推一下会发现是如下的矩阵,下面用win表示这个矩阵。

1, 0, 0, 0;
0, 1, 0, 0;
1, 0, 1, 0;
0, 1, 0, 1;

  [a1, a2, b1, b2]乘上一个什么样的矩阵会变成[a1, a2, a1 + b1, a2 + b2],我们手推一下会发现是如下的矩阵,下面用lost表示这个矩阵。

1, 0, 1, 0;
0, 1, 0, 1;
0, 0, 1, 0;
0, 0, 0, 1;

  我们观察题意发现区间修改和区间查询,所以考虑线段树维护矩阵,我们知道矩阵乘法具有结合律,我们对于茉美香赢赢输输赢这五个操作会得到乘法是[a1, a2, b1, b2] * win * win * lost * lost * win,那么我们会发现[a1, a2, b1, b2]只出现了一次,4 * 4大小的win或者lost出现了很多次,所以我们线段树上维护这样的4 * 4大小的矩阵乘法就行了,最后拿出来乘以[a1, a2, b1, b2]这个矩阵即可。但是这题要求翻转,如果每次翻转我们重新算就很复杂, 所以我们多维护一个矩阵,也就是考虑线段树维护两个矩阵,一个表示正确的状态,另一个表示翻转后的状态,这样的话我们每次进行修改操作,递归到一个被包含的区间可以直接交换两个矩阵并且打上一个懒标记,这样会大大降低时间复杂度。

#include <iostream>
#include <cstring>

#define ls u << 1
#define rs u << 1 | 1

const int N = 1e6 + 10;

inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a > b ? b : a;}


const int MOD = 1e9 + 7;
void add(int &a, int b) {
	a += b;
	if (a >= MOD) a -= MOD;
}
void del(int &a, int b) {
	a -= b;
	if (a < 0) a += MOD;
}
template <typename T>

struct Matrix{

	T a[4][4];

	Matrix<T> operator*(const Matrix<T>& B)const {

		Matrix<T> res;
		memset(res.a, 0, sizeof res.a);
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				for (int k = 0; k < 4; k++)
					add(res.a[i][j], 1ll * a[i][k] * B.a[k][j] % MOD);
			}
		}
		return res;
	}

	void print() {
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) std::cout << a[i][j] << " \n"[j == 3];
	}
};

int n, m;

char str[N];
int a1, a2, b1, b2;

struct Node{
	Matrix<int> A, B;

	int tag;
}tr[N << 2];

inline void pushup(int u){
	tr[u].A = tr[ls].A * tr[rs].A;
	tr[u].B = tr[ls].B * tr[rs].B;
}

inline void build(int u, int L, int R){
	memset(tr[u].A.a, 0, sizeof tr[u].A.a), memset(tr[u].B.a, 0, sizeof tr[u].B.a);
	if(L == R){
		if(str[L] == '1'){//win
			tr[u].A.a[0][0] = 1, tr[u].A.a[0][1] = 0, tr[u].A.a[0][2] = 0, tr[u].A.a[0][3] = 0;
			tr[u].A.a[1][0] = 0, tr[u].A.a[1][1] = 1, tr[u].A.a[1][2] = 0, tr[u].A.a[1][3] = 0;
			tr[u].A.a[2][0] = 1, tr[u].A.a[2][1] = 0, tr[u].A.a[2][2] = 1, tr[u].A.a[2][3] = 0;
			tr[u].A.a[3][0] = 0, tr[u].A.a[3][1] = 1, tr[u].A.a[3][2] = 0, tr[u].A.a[3][3] = 1;
			
			tr[u].B.a[0][0] = 1, tr[u].B.a[0][1] = 0, tr[u].B.a[0][2] = 1, tr[u].B.a[0][3] = 0;
			tr[u].B.a[1][0] = 0, tr[u].B.a[1][1] = 1, tr[u].B.a[1][2] = 0, tr[u].B.a[1][3] = 1;
			tr[u].B.a[2][0] = 0, tr[u].B.a[2][1] = 0, tr[u].B.a[2][2] = 1, tr[u].B.a[2][3] = 0;
			tr[u].B.a[3][0] = 0, tr[u].B.a[3][1] = 0, tr[u].B.a[3][2] = 0, tr[u].B.a[3][3] = 1;
		
		}else{
			tr[u].B.a[0][0] = 1, tr[u].B.a[0][1] = 0, tr[u].B.a[0][2] = 0, tr[u].B.a[0][3] = 0;
			tr[u].B.a[1][0] = 0, tr[u].B.a[1][1] = 1, tr[u].B.a[1][2] = 0, tr[u].B.a[1][3] = 0;
			tr[u].B.a[2][0] = 1, tr[u].B.a[2][1] = 0, tr[u].B.a[2][2] = 1, tr[u].B.a[2][3] = 0;
			tr[u].B.a[3][0] = 0, tr[u].B.a[3][1] = 1, tr[u].B.a[3][2] = 0, tr[u].B.a[3][3] = 1;
			
			tr[u].A.a[0][0] = 1, tr[u].A.a[0][1] = 0, tr[u].A.a[0][2] = 1, tr[u].A.a[0][3] = 0;
			tr[u].A.a[1][0] = 0, tr[u].A.a[1][1] = 1, tr[u].A.a[1][2] = 0, tr[u].A.a[1][3] = 1;
			tr[u].A.a[2][0] = 0, tr[u].A.a[2][1] = 0, tr[u].A.a[2][2] = 1, tr[u].A.a[2][3] = 0;
			tr[u].A.a[3][0] = 0, tr[u].A.a[3][1] = 0, tr[u].A.a[3][2] = 0, tr[u].A.a[3][3] = 1;
		
		}

		return ;
	}
	
	int mid = L + R >> 1;
	build(ls, L, mid);
	build(rs, mid + 1, R);
	
	pushup(u);
}

inline void pushdown(int u){
	if(tr[u].tag & 1){
		for(int i = 0; i < 4; i ++)
			for(int j = 0; j < 4; j ++){
				std::swap(tr[ls].A.a[i][j], tr[ls].B.a[i][j]);
				std::swap(tr[rs].A.a[i][j], tr[rs].B.a[i][j]);
			}
		tr[ls].tag ++;
		tr[rs].tag ++;
		tr[u].tag = 0;
	}
}

inline void modify(int u, int L, int R, int l, int r){
	if(L >= l && R <= r){
		for(int i = 0; i < 4; i ++)
			for(int j = 0; j < 4; j ++){
				std::swap(tr[u].A.a[i][j], tr[u].B.a[i][j]);
			}
		tr[u].tag ++;
		return ;
	}
	
	pushdown(u);
	
	int mid = L + R >> 1;
	if(l <= mid)	modify(ls, L, mid, l, r);
	if(r > mid)	modify(rs, mid + 1, R, l, r);
	
	pushup(u);
}

inline Matrix<int> query(int u, int L, int R, int l, int r){
	if(L >= l && R <= r)	return tr[u].A;
	
	pushdown(u);
	
	int mid = L + R >> 1;
	
	if(r <= mid)	return query(ls, L, mid, l, r);
	if(l > mid)	return query(rs, mid + 1, R, l, r);
	
	return query(ls, L, mid, l, r) * query(rs, mid + 1, R, l, r);

}

inline void solve(){
	std::cin >> n >> m;
	std::cin >> a1 >> b1 >> a2 >> b2;
	
	std::cin >> (str + 1);
	build(1, 1, n);
	
	while(m --){
		int op, l, r;
		std::cin >> op >> l >> r;
		if(op == 1){
			modify(1, 1, n, l, r);
		}else{
			Matrix<int> MY;
			memset(MY.a, 0, sizeof MY.a);
			MY.a[0][0] = a1, MY.a[0][1] = a2, MY.a[0][2] = b1, MY.a[0][3] = b2;
			Matrix<int> res = MY * query(1, 1, n, l, r);
		
			int ans = 0;
			add(ans, 1ll * res.a[0][0] * res.a[0][1] % MOD);
			del(ans, 1ll * res.a[0][2] * res.a[0][3] % MOD);
			std::cout << ans << '\n';
		}
	}
}

int main(void){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);

	int _ = 1;
	//std::cin >> _;
	while(_ --)	solve();
	
	return 0;
}

标签:广州大学,hard,矩阵,ACM,a1,int,a2,b1,b2
From: https://www.cnblogs.com/qdhys/p/17308108.html

相关文章

  • git reset [--soft| --mixed| --hard] [commit]
    【参考】https://www.jianshu.com/p/c6927e80a01d【理解】--soft改变最轻,将已提交变成uncommit状态,工作区内容不变--mixed次之,将已提交变成unstage状态,工作区不变--hard最严重,全部撤回,工作区改变 执行gitreset--hard 后可使用gitreflog查看更改 ......
  • postgresSQL Extended Query执行过程和sharding-proxy的处理
    pgExtendedQueryPostgreSQL:Documentation:15:55.2. MessageFlow多个阶段,可复用Parse→DESCRIBEstatement→SYNCParse解析,将sql文本字符串,解析成namedpreparedStatement语句(生命周期随session)占位符和参数类型Describe获取元数据,返回pst参数描述......
  • 【ACM博弈论】SG函数入门(1):从巴什博奕到尼姆游戏
    在我小时候以前做题的时候,遇到博弈题往往都是漫无目的地打表找规律,或者找一些特殊情况但是没有很好的分析方法。其实博弈题是有比较套路的解题方法的,那就是利用SG函数,第一节不会讲到SG函数的具体用法,我们先来博弈入个门,学习一下最基本的博弈类型:Nim游戏。......
  • sharding-jdbc使用及原理
     基本思想:一条sql,经过分片,改造成多条sql,执行,最后合并结果集,得到预期结果。一、基本使用pom(基于5.2.0)<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core</artifactId><version>5.2.0</version>......
  • 分库分表之ShardingSphere
    为什么要分库分表用户请求量太大单服务器TPS、内存、IO都是有上限的,需要将请求打散分布到多个服务器。单库数据量太大单个数据库处理能力有限;单库所在服务器的磁盘空间有限;单库上的操作IO有瓶颈。单表数据量太大查询、插入、更新操作都会变慢,在加字段、加......
  • 项目打包优化-HardSourceWebpackPlugin
    项目优化的方法HardSourceWebpackPlugin是一个插件,安装的方式npmihard-source-webpack-plugin引入文件,进行config文件的配置进行文件的热加载的,一个项目启动或者打包的时间,超过40s的时候,可以进行项目的优化和热加载。文件的加载,首先hard-source-webpack-plugin会进行文......
  • ShardingSphereJDBC+MybatisPlus实现分库分表
    前言这篇是ShardingSphere-JDBC+Springboot+MybatisPlus+Druid分库分表的简单例子,我们用一个订单表为例,通过简单配置实现数据分片到多个数据库的多个表中。主要配置和代码已经在文中给出,完整例子可以参考GitHub-fruitbasket-litchi-shardingjdbc。准备数据库在一个或两个My......
  • 【ACM算法竞赛日常训练】DAY10题解与分析【月月给华华出题】【华华给月月出题】| 筛法
    DAY10共2题:月月给华华出题华华给月月出题难度较大。......
  • shardingsphere-jdbc
    shardingsphere-jdbc5.1.1版本<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.1.1</version&......
  • ACM预备队-大一下学期week(3)集训
    1.饿饿,饭饭2题目链接:饿饿饭饭2-Problem-DaimayuanOnlineJudge1#include<iostream>2usingnamespacestd;34intmain(){5intT;6cin>>T;7while(T--){8intn;9cin>>n;10inta[n];1......