[NOI Online #3]魔法值

题目

  点这里看题目。

分析

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

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

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

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

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

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

  一个向量与矩阵相乘,时间是(O(n^2))的。因此,我们可以将求出(C^{a_i})的时间缩减到(O(n^2)),总时间(O(n^2sum 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( '
' );
	}
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/12990955.html