【考题·数学】矩阵游戏(数学推导)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89105576

问题描述

LZK发明一个矩阵游戏,大家一起来玩玩吧,有一个N行M列的矩阵。第一行的数字是1,2,…M,第二行的数字是M+1,M+2…2*M,以此类推,第N行的数字是(N-1)*M+1,(N-1)M+2…NM。

例如,N=3,M=4的矩阵是这样的:

1 2 3

4 5 6

7 8 9

10 11 12

对于身为智慧之神的LZK来说,这个矩阵过于无趣.于是他决定改造这个矩阵,改造会进行K次,每次改造会将矩阵的某一行或某一列乘上一个数字,你的任务是计算最终这个矩阵内所有数字的和,输出答案对109+7取模。

题目大意

给定一个顺序标号的矩阵,有若干次操作使得某一行或某一列乘上某一个数,求最后只一个矩阵的所有数之和。

题解

我们用数组 r i r_i 标记第 i i 行所有乘的数的积,用数组 s i s_i 标记第 j j 列所有乘的数的积。

通过观察,可以发现第 i i 行第 j j 列的数字编号为: m × ( i 1 ) + j m\times(i-1)+j

显然对于每一个数,乘法的顺序不会对结果产生任何影响,因此我们可以先处理横向的乘法。

在做完横向的乘法以后,我们需要得到第j列所有数的和 s u m j sum_j ,则有:
s u m j   =   i = 1 n r i × [ m ( i 1 ) + j ] sum_j\ =\ \sum_{i=1}^{n}r_i\times[m(i-1)+j]
通过乘法分配律展开,得到:
s u m j   =   i = 1 n r i × m ( i 1 ) + i = 1 n r i × j sum_j\ =\ \sum_{i=1}^{n}r_i\times m(i-1)+\sum_{i=1}^{n}r_i\times j
再将右边部分的 j j 提出,得到:
s u m j   =   i = 1 n r i × m ( i 1 ) + j × i = 1 n r i sum_j\ =\ \sum_{i=1}^{n}r_i\times m(i-1)+j\times \sum_{i=1}^{n}r_i
这样,我们就将算式化简为了两个部分,用字母 k 1 k_1 k 2 k_2 来换元,则:
k 1   =   i = 1 n r i × m ( i 1 ) k_1\ =\ \sum_{i=1}^{n}r_i\times m(i-1)
k 2   =   j × i = 1 n r i k_2\ =\ j\times \sum_{i=1}^{n}r_i
其中 k 1 k_1 k 2 k_2 都是和 i i 有关而和 j j 无关的常量,因此我们可以在枚举j的使用用 O ( n ) O(n) 的时间求出结果。这样,我们就可以用带有 k 1 k_1 k 2 k_2 的代数式来表示 s u m j sum_j 的具体数值:
s u m j   =   k 1 + k 2 × j sum_j\ =\ k1+k2\times j
显然,这个算是也可以使用 O ( 1 ) O(1) 的时间复杂度求出。那么我们就可以答案的表示方法:
a n s   =   i = 1 m s u m i ans\ =\ \sum_{i=1}^{m}sum_i
由于需要枚举 j j ,因此时间复杂度是 O ( n + m ) O(n+m)

注意:

  • 所有涉及具体数值的变量都要开 l o n g l o n g long long
  • 在做乘法和取模时,不要全部乘完再取模,要变乘变取模。

代码如下:

#include <bits/stdc++.h>

#define LL long long

using namespace std;

const LL N = 1000010;
const  LL P = 1e9 + 7;
LL n,m,k;
LL s[N],r[N];

int main(void)
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%lld %lld %lld",&n,&m,&k);
	for (LL i=1;i<=n;++i) r[i] = 1;
	for (LL i=1;i<=m;++i) s[i] = 1;
	for (LL i=1;i<=k;++i)
	{
		LL x;
		LL  y;
		char c = getchar();
		while (c!='R' && c!='S') c = getchar();
		scanf("%lld %lld",&x,&y);
		if (c == 'S') s[x] = (s[x]*y)%P;
		if (c == 'R') r[x] = (r[x]*y)%P; 
	} 
	LL sum1 = 0, sum2 = 0,ans = 0;
	for (LL i=1;i<=n;++i) 
		sum1 = (r[i]*m%P*(i-1)%P + sum1)%P;
	// sum1 = sigma r[i]*m*(i-1)
	for (LL i=1;i<=n;++i)
	    sum2 = (sum2+r[i])%P;
	// sum2 = sigma r[i] 
	for (LL j=1;j<=m;++j)
	    ans = (ans + (sum1+sum2*j%P)%P*s[j]%P)%P;
	// ans = sigma (sum1+sum2*j)*s[j]
    printf("%lld\n",ans);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/89105576