数字游戏(number)

数字游戏(number)

题目大意

不高兴找到了一个N行M列的矩阵。矩阵的第一行数字为 123...M1,2,3,...,M,第二行数字为 M+1M+2...2×MM+1,M+2,...,2 \times M,第 NN 行数字为 (N1)×M+1(N1)×M+2...N×M(N-1)\times M+1,(N-1) \times M+2,...,N \times M

例如,对于 N=3M=4N=3,M=4

1  2  3  4
5  6  7  8
9 10 11 12

当然这样的矩阵是无趣的,所有他选择了其中一行或一列,将其乘以非负数,会进行 KK 次。最后他想知道矩阵中所有值的总和。由于总和可能会很大,需要总和模 109+7\color{red}{由于总和可能会很大,需要总和模 \ 10^9+7。}

数据范围:

对于 50%50\% 的数据,1<=N,M<=10001<=N,M<=1000

对于 100%100\% 的数据,1<=N,M<=1000000,1<=K<=1000,0<=X,Y<=1091<=N,M<=1000000,1<=K<=1000,0<=X,Y<=10^9

解题思路

注意:由于本蒟蒻的习惯,可能会对大家造成影响。

i=1n\sum_{i=1}^{n} \to 这是求和。

i=1n\sum\limits_{i=1}^{n} \to 这是循环。

一开始可以想到对于所有操作,暴力修改一遍,时间复杂度为 O(nk)O(nk),可拿 50pts50pts(艹,为什么模拟赛时没打暴力?我是sb吗???

继续思考,显然可以将所有的操作全部合起来,搞一个离线算法。

即记 hangihang_i 为第 ii 行要乘上的非负数,lieilie_i 为第 ii 列要乘上的非负数。

由于我们不能同时修改行和列,所以先选个修改列,再修改行吧。

此时可以发现,对于原矩阵 aaai,j=ai1,j+ma_{i,j} = a_{i-1,j} + m,所以在原矩阵中,第 ii 行比第 i1i-1 行多 m2m^2,因此可以将第一行当做基准,依次求得第二行,第三行....第 nn 行。

1    2    3    4
1+m  2+m  3+m  4+m
1+2m 2+2m 3+2m 4+2m

发现规律后,就可以开始修改列了,此时又可以发现,对于修改完列后的矩阵 bbbi,jb_{i,j}bi1,jb_{i-1,j}m×liejm\times lie_j,第 ii 行比第 i1i-1 行多 a=k=1mliek×ma=\sum_{k=1}^{m} lie_k \times m

显然对于修改列后的矩阵 bb,每一行的相差数也是不变的。

例如将第 22 列乘上 22

1  4  3  4
5 12  7  8
9 20 11 12

此时 lielie 数组为

1 2 1 1

bi,j=bi1,j+m×liejb_{i,j} = b_{i-1,j}+m\times lie_j

先计算修改完列后的矩阵 bb11 行的和为 b=k=1mliek×ib=\sum_{k=1}^{m} lie_k \times iii 为原矩阵 aa11 行的数)。

由上可得,修改完列后的矩阵 bbii 行的和为 b+a×(i1)b+a \times (i-1)

则答案矩阵 ccii 行的和就为修改完列后的矩阵 bbii 行的和乘上 hangihang_i,即为 b+a×(i1)×hangib+a \times (i-1) \times hang_i

此时已经可以求得修改完列后的矩阵 bb 每一行的和了,乘上 hangihang_i 再累加就结束了。

然后,就没有然后了。

十年 OI 一场空,不开 long long 见祖宗\color{red}{十年 \ OI \ 一场空,不开 \ long \ long \ 见祖宗}

AC CODE

#include<bits/stdc++.h>
#define int long long
const int mod = 1e9 + 7;
using namespace std;

int n, m, k;
int a, b, ans;
int lie[1000005], hang[1000005];

signed main()
{
	scanf("%lld%lld%lld", &n, &m, &k);
	
	for(int i = 1; i <= m; ++i) lie[i] = 1;
	for(int i = 1; i <= n; ++i) hang[i] = 1;
	
	for(int i = 1; i <= k; ++i)
	{
		char c[5];
		int a, b;
		scanf("%s", c);
		scanf("%lld%lld", &a, &b);
		if(c[0] == 'R') hang[a] = hang[a] * b % mod;
		else lie[a] = lie[a] * b % mod;
	}
	
	for(int i = 1; i <= m; ++i)
	{
		a = (a + lie[i] * m % mod) % mod;
		// a += lie[i] * m;
		// 修改完列的矩阵 b 每一行的相差数。
		b = (b + lie[i] * i % mod) % mod;
		// b += lie[i] * i;
		// 求修改完列的矩阵 b 的第一行的和。
	}
	
	for(int i = 1; i <= n; ++i)
	{
		ans = (ans + (b + a * (i - 1) % mod) * hang[i] % mod) % mod;
		// ans += b + a * (i - 1) * hang[i];
		// 求答案,这不用说了吧。
	}
		
	printf("%lld", ans % mod);
	return 0;
}
posted @ 2021-08-05 09:27  蒟蒻orz  阅读(5)  评论(0编辑  收藏  举报  来源