【CCF-CSP】202312-4 宝藏

题目描述

西西艾弗岛上埋藏着一份宝藏,小 C 根据藏宝图找到了宝藏的位置。藏有宝藏的箱子被上了锁,旁边写着一些提示:

  • 给定 n 条指令,编号为1∼n,其中每条指令都是对一个双端队列的操作,队列中的元素均为 2×22×2 的矩阵
  • 在某些时刻,某一条指令可能会改变;
  • 在某些时刻,密码可以由以下方式计算:对于给定的指令区间[l,r],对初始为空的队列依次执行第 l∼r 条指令,将得到的队列里的所有矩阵从头到尾相乘,并将乘积矩阵中的所有元素对 998244353998244353 取模,得到的矩阵即为密码;特别地,若队列为空,则密码为单位矩阵;如果能分别计算出这些时刻的密码,将能够打开箱子的锁,从而获得宝藏。

经过小 C 的观察,每条指令的形式均为以下三种之一:

  1. 给定 2×22×2 的矩阵 A,将 A 插入队列的头部;
  2. 给定 2×22×2 的矩阵 B,将 B 插入队列的尾部;
  3. 若队列非空,删除队列中最晚被插入的矩阵。

小 C 将所有的时刻发生的事件均记录了下来。具体地,共有 m 个时刻,每个时刻可能会发生两种事件:

  1. 第 i 条指令改变,改变后的指令仍为以上三种形式之一;
  2. 给定指令区间[l,r],求依次执行第 l∼r 条指令得到的密码。

由于小 C 并不会这个问题,他向你发起了求助。你需要帮助小 C 求出所有类型为 22 的事件所对应的密码。

输入格式

从标准输入读入数据。

输入的第一行包含两个正整数n,m。

接下来 n 行,按顺序给出初始时刻的每条指令:

  • 输入的第一个正整数 v 描述这条指令的形式,保证 v 为 1,2,31,2,3 中的一种。
  • 若 v=1,接下来给出四个非负整数 A1,1​,A1,2​,A2,1​,A2,2​,表示操作为将 2×22×2 的矩阵 A 插入队列的头部;
  • 若 v=2,接下来给出四个非负整数 B1,1​,B1,2​,B2,1​,B2,2​,表示操作为将 2×22×2 的矩阵 B 插入队列的尾部;
  • 若 v=3,表示操作为若队列非空,删除队列中最晚被插入的矩阵;

接下来 m 行,按顺序给出每个时刻发生的事件:

  • 输入的第一个正整数 v 描述这个事件的类型,保证 v 为 1,21,2 中的一种。
  • 若 v=1,接下来给出一个正整数 i 与一条指令,表示将第 i 条指令更新为当前输入的指令,指令的输入格式与初始时刻指令的输入格式相同。
  • 若 v=2,接下来给出两个正整数l,r,你需要求出依次执行第 ∼r 条指令得到的密码。

输出格式

输出到标准输出。

对于所有类型为 2的事件,输出一行四个非负整数 C1,1​,C1,2​,C2,1​,C2,2​,表示该时刻的密码 C。

代码(暴力做法35分)

#include <bits/stdc++.h>
#define N 100010
using namespace std;
typedef long long ll;

const int mod=998244353;
int n,m,k,l,r;
struct matrix{
	int id,type;
	ll a[2][2];
}t[N];

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	t[i].id=i;
    	cin>>t[i].type;
		if(t[i].type==1||t[i].type==2)
			cin>>t[i].a[0][0]>>t[i].a[0][1]>>t[i].a[1][0]>>t[i].a[1][1];
    }
    for(int i=1;i<=m;i++){
    	cin>>k>>l>>r;
    	if(k==1){
    		t[l].type=r;
    		if(t[l].type==1||t[l].type==2)
    			cin>>t[l].a[0][0]>>t[l].a[0][1]>>t[l].a[1][0]>>t[l].a[1][1];
		}
		else{
			deque<matrix> dq;
			for(int j=l;j<=r;j++){
				if(t[j].type==1) dq.push_front(t[j]);
				else if(t[j].type==2) dq.push_back(t[j]);
				else if(dq.size()){
					if(dq.front().id>dq.back().id) dq.pop_front();
					else dq.pop_back();
				}
			}
			ll ans[2][2]={1,0,0,1},b[2][2];
			while(dq.size()){
				matrix tmp=dq.front();
				dq.pop_front();
				for(int s=0;s<2;s++)
					for(int t=0;t<2;t++) b[s][t]=ans[s][t];
				for(int s=0;s<2;s++)
					for(int t=0;t<2;t++)
						ans[s][t]=(b[s][0]*tmp.a[0][t]+b[s][1]*tmp.a[1][t])%mod;	
			}
			cout<<ans[0][0]<<" "<<ans[0][1]<<" "<<ans[1][0]<<" "<<ans[1][1]<<endl;
		}
    }
    return 0;
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值