Newcoder 110 D.矩阵(水~)

186 篇文章 0 订阅

Description

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

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

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

现在,给定 a , b , c , d a,b,c,d abcd的四个种子可以通过 X o r s h i f t Xorshift 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) (hashfunction)

我们会给你另一个数字 p 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 n,Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd,p

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

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

p 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) (1n2000,1Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd<232,2p<109+7)

Output

C = A × B C = A \times B C=A×B C C C A A A矩阵乘以 B 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} ans===i=0n1j=0n1Cijp(n1i)n+(n1j)i=0n1j=0n1k=0n1AikBkjp(n1i)n+(n1j)k=0n1(i=0n1Aikp(n1i)n)(j=0n1Bkjpn1j)
时间复杂度降为 O ( n 2 ) O(n^2) O(n2),注意到直接开空间存 A , B 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} ak=i=0n1Aikp(n1i)n,bk=j=0n1Bkjpn1j
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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值