Newcoder 110 D.矩阵(水~)

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

Description

给定两个巨大的方块矩阵 A A B B (行数高达 7000 7000 ).请输出 A × B A\times B 的运算结果,且时限只有 2 s 2s

哈哈!对矩阵乘法的演进历史有些涉猎的人,应该能感受到在某 C P C CPC 上出现这样的题目有多不合理。

为了使这个问题成为可能(?),我们将减小 I / O I / O 大小。

现在,给定 a b c d a,b,c,d 的四个种子可以通过 X o r s h i f t Xorshift 随机数生成器生成输入矩阵。

这里是通过随机数生成器来产生矩阵的实现:

uint32_t x, y, z, w;
uint32_t xorshift() {
    uint32_t t = x;
    t ^= t << 11;
    t ^= t >> 8;
    x = y; y = z; z = w;
    w ^= w >> 19;
    w ^= t;
    return w & ((1 << 24) - 1);
}
void getInputMatrix(
    int n, uint32_t matrix[][7000],
    uint32_t a, uint32_t b, uint32_t c, uint32_t d
) {
    x = a; y = b; z = c; w = d;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            matrix[i][j] = xorshift();
        }
    }
}

另外,您应该将输出矩阵传递给哈希函数 ( h a s h f u n c t i o n ) (hash function)

我们会给你另一个数字 p p 来做这件事。

这里是哈希函数的实现。

const int MOD = 1000000007;
int hash(int n, long long matrix[][7000], int p) {
    long long v = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            v *= p;
            v += matrix[i][j];
            v %= MOD;
        }
    }
    return v;
}

Input

输入只包含一行,包含十个整数 n , A a , A b , A c , A d , B a , B b , B c , B d , p n,A_a,A_b,A_c,A_d,B_a,B_b,B_c,B_d,p

扫描二维码关注公众号,回复: 3640047 查看本文章

矩阵 A A 是通过 n , A a , A b , A c , A d n,A_a,A_b,A_c,A_d 构建 g e t I n p u t M a t r i x ( ) getInputMatrix() 的。

矩阵 B B 是通过 n , B a , B b , B c , B d n,B_a,B_b,B_c,B_d 构建 g e t I n p u t M a t r i x ( ) getInputMatrix() 的。

p p 是哈希函数。

( 1 n 2000 , 1 A a , A b , A c , A d , B a , B b , B c , B d &lt; 2 32 , 2 p &lt; 1 0 9 + 7 ) (1\le n\le 2000,1\le A_a,A_b,A_c,A_d,B_a,B_b,B_c,B_d&lt; 2^{32},2\le p&lt;10^9+7)

Output

C = A × B C = A \times B C C A A 矩阵乘以 B B 的结果

请输出一个整数,它是$hash(n,C,p) $的结果

Sample Input

1 2 3 4 5 6 7 8 9 10

Sample Output

50873769

Solution
a n s = i = 0 n 1 j = 0 n 1 C i j p ( n 1 i ) n + ( n 1 j ) = i = 0 n 1 j = 0 n 1 k = 0 n 1 A i k B k j p ( n 1 i ) n + ( n 1 j ) = k = 0 n 1 ( i = 0 n 1 A i k p ( n 1 i ) n ) ( j = 0 n 1 B k j p n 1 j ) \begin{array}{lcl} ans&amp;=&amp;\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}C_{ij}\cdot p^{(n-1-i)\cdot n+(n-1-j)}\\ &amp;=&amp;\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}\sum\limits_{k=0}^{n-1}A_{ik}\cdot B_{kj}\cdot p^{(n-1-i)\cdot n+(n-1-j)}\\ &amp;=&amp;\sum\limits_{k=0}^{n-1}(\sum\limits_{i=0}^{n-1}A_{ik}\cdot p^{(n-1-i)\cdot n})\cdot (\sum\limits_{j=0}^{n-1}B_{kj}\cdot p^{n-1-j}) \end{array}
时间复杂度降为 O ( n 2 ) O(n^2) ,注意到直接开空间存 A , B A,B 会爆内存,直接维护
a k = i = 0 n 1 A i k p ( n 1 i ) n , b k = j = 0 n 1 B k j p n 1 j a_k=\sum\limits_{i=0}^{n-1}A_{ik}\cdot p^{(n-1-i)\cdot n},b_k=\sum\limits_{j=0}^{n-1}B_{kj}\cdot p^{n-1-j}
Code

#include<cstdio>
using namespace std;
typedef long long ll;
typedef unsigned uint32_t;
const int maxn=7000;
uint32_t x,y,z,w;
uint32_t xorshift() 
{
    uint32_t t=x;
    t^=t<<11;
    t^=t>>8;
    x=y;y=z;z=w;
    w^=w>>19;
    w^=t;
    return w&((1<<24)-1);
}
#define mod 1000000007
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod;
}
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
uint32_t Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd,p;
int n,f[maxn],g[maxn],A[maxn],B[maxn];
int main()
{
	scanf("%d%u%u%u%u%u%u%u%u%u",&n,&Aa,&Ab,&Ac,&Ad,&Ba,&Bb,&Bc,&Bd,&p);
	p%=mod;
	f[0]=g[0]=1;
	for(int i=1;i<n;i++)f[i]=mul(f[i-1],p);
	p=mul(f[n-1],p);
	for(int i=1;i<n;i++)g[i]=mul(g[i-1],p);
	x=Aa,y=Ab,z=Ac,w=Ad;
	for(int i=0;i<n;i++)
		for(int k=0;k<n;k++)
			A[k]=add(A[k],mul(xorshift(),g[n-1-i]));
	x=Ba,y=Bb,z=Bc,w=Bd;
	for(int k=0;k<n;k++)
		for(int j=0;j<n;j++)
			B[k]=add(B[k],mul(xorshift(),f[n-1-j]));
	int ans=0;
	for(int k=0;k<n;k++)ans=add(ans,mul(A[k],B[k]));
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/83110395
110