[NOI Online #3]魔法值

题目

  点这里看题目。

分析

  我们不难想到,对于系数进行一下的拆分:

\[\begin{aligned} f(u,j)&=\bigoplus_{(u,v)\in E} f(v,j-1)\\ &=\bigoplus_{(u,v)\in E}\bigoplus_{(v,w)\in E} f(w,j-2)\\ &...\\ &=\bigoplus_{x\in V} f(x,0)\times C^j_{u,x} \end{aligned} \]

  其中,\(C^j_{u,x}\)表示恰好走\(j\)步时,从\(u\)\(x\)的方案数
  根据异或的性质,我们实际上只会关心\(C^j_{u,x}\)的奇偶性。
  怎么求这个东西呢?我们可以想到用矩阵乘法。
  初始矩阵就是邻接矩阵:

\[T_{i,j}= \begin{cases} 1 & (i,j)\in E\\ 0 & (i,j)\not \in E \end{cases} \]

  现在对于一个询问\(a_i\),我们发现我们需要的系数实际上就是\(T^{a_i}\),这个东西可以用矩阵快速幂快速地求出来。
  单纯地按照上面的方法,时间是\(O(n^3\sum\log_2a)\),不妙。
  再仔细想一想,我们明明只需要从 1 出发的信息(只需要\(C^{a_i}_1\)),使用矩阵快速幂却多算了很多。
  考虑\(C^{a_i}_1\)实际上是:

\[ \boldsymbol v = \{1,0,0,...\}\\ C^{a_i}_1=v\times T^{a_i} \]

  一个向量与矩阵相乘,时间是\(O(n^2)\)的。因此,我们可以将求出\(C^{a_i}\)的时间缩减到\(O(n^2)\),总时间\(O(n^2\sum \log_2a)\),可过。
  实际操作中,我们需要预处理出\(T\)的倍增,避免每次重新计算,导致复杂度退化。

代码

#include <cstdio>
#include <cstring>

typedef long long LL;

const int MAXN = 105, MAXLOG = 40;

template<typename _T>
void read( _T &x )
{
	x = 0;char s = getchar();int f = 1;
	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
	if( 9 < x ){ write( x / 10 ); }
	putchar( x % 10 + '0' );
}

struct matrix
{
	bool mat[MAXN][MAXN];
	int n, m;
	matrix() { n = m = 0, memset( mat, false, sizeof mat ); }
	matrix( const int N, const int M ) { n = N, m = M, memset( mat, false, sizeof mat ); }
	bool* operator [] ( const int indx ) { return mat[indx]; }
	
	matrix operator * ( matrix b ) const
	{
		matrix ret = matrix( n, b.m );
		for( int i = 1 ; i <= ret.n ; i ++ )
			for( int k = 1 ; k <= m ; k ++ )
				if( mat[i][k] )
					for( int j = 1 ; j <= ret.m ; j ++ )
						ret[i][j] ^= mat[i][k] & b[k][j];
		return ret;
	}
	
	void operator *= ( matrix b ) { *this = *this * b; }
};

matrix B[MAXLOG], A;
LL f[MAXN];
int N, M, Q;

int main()
{
	read( N ), read( M ), read( Q );
	B[0] = matrix( N, N );
	for( int i = 1 ; i <= N ; i ++ ) read( f[i] );
	for( int i = 1, a, b ; i <= M ; i ++ )
		read( a ), read( b ), B[0][a][b] = B[0][b][a] = 1;
	for( int i = 1 ; i <= 32 ; i ++ ) B[i] = B[i - 1] * B[i - 1];
	while( Q -- )
	{
		LL a; read( a );
		A = matrix( 1, N ), A[1][1] = 1;
		for( int i = 32 ; ~ i ; i -- )
			if( a >> i & 1 )
				A *= B[i];
		LL ans = 0;
		for( int i = 1 ; i <= N ; i ++ ) 
			if( A[1][i] )
				ans ^= f[i];
		write( ans ), putchar( '\n' );
	}
	return 0;
}
posted @ 2020-05-30 09:38  crashed  阅读(119)  评论(0编辑  收藏  举报