【JZOJ】6277. 矩阵游戏

本文深入探讨了矩阵操作中的一种高效算法,通过预处理行和列的累积效果,避免了重复计算,显著提高了大规模矩阵运算的效率。文章详细介绍了算法的实现过程,包括关键的数学公式和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Time Limits: 1000 ms Memory Limits: 524288 KB

Input

Output

Sample Input
Sample Input1

3 4 4
R 2 4
S 4 1
R 3 2
R 2 0

Sample Input2

2 4 4
S 2 0
S 2 3
R 1 5
S 1 3

Sample Output
Sample Output1

94

Sample Output2

80

Data Constraint

Hint

思路

考虑这个矩阵原来的每一行,每一列的Sum值,有
行:Sumi=(((i−1)∗M+1)+i∗M)∗M/2Sum_i=(((i-1)*M+1)+i*M)*M/2Sumi=(((i1)M+1)+iM)M/2
列:Sumi=(i+((N−1)∗M+i))∗N/2Sum_i=(i+((N-1)*M+i))*N/2Sumi=(i+((N1)M+i))N/2
先假定Ans值为原矩阵值总和。

我们可以先预处理出每一行每一列上乘的数字总积。
对于一个格子,其最多被一行一列所影响,先考虑其中一个的影响。
那么有Ans+=Sumi∗(Ki−1)Ans+=Sum_i*(K_i-1)Ans+=Sumi(Ki1)(其中KiK_iKi为该行(列)总积)
(Ki−1)(K_i-1)(Ki1)是因为先前Ans里已预装了原矩阵的总和)
我们对于每一行每一列(有影响的),都做一次这个操作。

考虑那些重复的点,假定AijA_{ij}Aij原矩阵第i行第j的值。
且第i行的KiK_iKi值为X,第j列的KjK_jKj值为Y。
那么,AijA_{ij}Aij本来对答案的贡献应该是Aij∗X∗YA_{ij}*X*YAijXY
但是现在,Ans里AijA_{ij}Aij对答案贡献实际上为Aij∗(X−1)+Aij∗(Y−1)+AijA_{ij}*(X-1)+A_{ij}*(Y-1)+A_{ij}Aij(X1)+Aij(Y1)+Aij
化简为Aij∗X+Aij∗Y−AijA_{ij}*X+A_{ij}*Y-A_{ij}AijX+AijYAij
那么此时Ans应该做如下操作Ans+=Aij∗X∗Y−(Aij∗X+Aij∗Y−Aij)Ans+=A_{ij}*X*Y-(A_{ij}*X+A_{ij}*Y-A_{ij})Ans+=AijXY(AijX+AijYAij)
化简得Ans+=Aij∗(X−1)∗(Y−1)Ans+=A_{ij}*(X-1)*(Y-1)Ans+=Aij(X1)(Y1)
根据矩阵的定义,我们有:Aij=(i−1)∗M+jA_{ij}=(i-1)*M+jAij=(i1)M+j
带入Ans更改式得:Ans+=((i−1)∗M+j)∗(X−1)∗(Y−1)Ans+=((i-1)*M+j)*(X-1)*(Y-1)Ans+=((i1)M+j)(X1)(Y1)
即:Ans+=(i−1)∗M∗(X−1)∗(Y−1)+(X−1)∗(Y−1)∗jAns+=(i-1)*M*(X-1)*(Y-1)+(X-1)*(Y-1)*jAns+=(i1)M(X1)(Y1)+(X1)(Y1)j

考虑每一行都会与每一列相交,我们可以预处理出
Sum1=∑i=1N(Ki−1)Sum1=\begin{matrix}\sum_{i=1}^N (K_i-1)\end{matrix} Sum1=i=1N(Ki1)
Sum2=∑i=1N((Ki−1)∗i)Sum2=\begin{matrix}\sum_{i=1}^N ((K_i-1)*i)\end{matrix} Sum2=i=1N((Ki1)i)

直接带入最后的Ans更改式值得:
Ans+=(i−1)∗M∗(X−1)∗Sum1+(X−1)∗Sum2Ans+=(i-1)*M*(X-1)*Sum1+(X-1)*Sum2Ans+=(i1)M(X1)Sum1+(X1)Sum2

代码

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const long long ONE=1;
const int MAXK=100005;
const int MAXN=1000005;
const int MOD=1000000007;
int N,M,K,Cnt1,Cnt2;
int vis1[MAXN],vis2[MAXN];
long long p1[MAXN],p2[MAXN];
struct node{int x,y;};
node s1[MAXK],s2[MAXK];
long long Sum1,Sum2;
vector<int>P1,P2;
long long Ans;
bool cmp(node A,node B){
	return A.x<B.x||(A.x==B.x&&A.y<B.y);
}
long long Get1(int x){
	return ((ONE*(x-1)*M+1+ONE*x*M)*M/2)%MOD;
}
long long Get2(int x){
	return ((x+ONE*(N-1)*M+x)*N/2)%MOD;
}
int main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d%d%d",&N,&M,&K);
	for(int i=1;i<=K;i++){
		int X,Y;char c[5]={0};
		scanf("%s%d%d",c+1,&X,&Y);
		if(c[1]=='R')s1[++Cnt1].x=X,s1[Cnt1].y=Y;
		if(c[1]=='S')s2[++Cnt2].x=X,s2[Cnt2].y=Y;
	}
	sort(s1+1,s1+Cnt1+1,cmp);
	sort(s2+1,s2+Cnt2+1,cmp);
	for(int i=1;i<=N;i++)p1[i]=1;
	for(int i=1;i<=M;i++)p2[i]=1;
	for(int i=1;i<=Cnt1;i++){
		p1[s1[i].x]=(ONE*p1[s1[i].x]*s1[i].y)%MOD;
		if(!vis1[s1[i].x]){
			vis1[s1[i].x]=1;
			P1.push_back(s1[i].x);
		}
	}
	for(int i=1;i<=Cnt2;i++){
		p2[s2[i].x]=(ONE*p2[s2[i].x]*s2[i].y)%MOD;
		if(!vis2[s2[i].x]){
			vis2[s2[i].x]=1;
			P2.push_back(s2[i].x);
		}
	}
	int siz1=P1.size();
	int siz2=P2.size();
	for(int i=1;i<=N;i++)
		Ans=(Ans+Get1(i))%MOD;
	for(int i=0;i<siz1;i++)
		Ans=(Ans+ONE*(p1[P1[i]]-1)*Get1(P1[i]))%MOD;
	for(int i=0;i<siz2;i++){
		Ans=(Ans+ONE*(p2[P2[i]]-1)*Get2(P2[i]))%MOD;
		Sum1=(Sum1+(p2[P2[i]]-1))%MOD;
		Sum2=(Sum2+ONE*(p2[P2[i]]-1)*P2[i])%MOD;
	}
	for(int i=0;i<siz1;i++)
		Ans=(Ans+((((((ONE*(p1[P1[i]]-1)*(P1[i]-1))%MOD)*Sum1)%MOD)*M)%MOD)+((ONE*(p1[P1[i]]-1)*Sum2)%MOD))%MOD;
	printf("%lld\n",Ans);
}
/*
3 4 5
R 1 1
R 2 1
R 3 1
S 1 4
S 2 0
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值