题解 P6569 【[NOI Online #3 提高组]魔法值(民间数据)】

17 篇文章 0 订阅
9 篇文章 0 订阅

题意分析

给定 n n n 个点, m m m 条边的无向图,第 i i i 个点的点权是 f [ i ] f[i] f[i] ,每次的点权会变化成为与其相连的点的异或和,给你 q q q 个查询,每一个查询输出第 q q q 次变化后 1 1 1 号点的点权。

思路

好了,题意理解成这样,大概就可以想象出一种暴力做法,但是会超时(这个错解在官方题解中有提及),可以自行算出复杂度证伪

第三场NOI Online试题-魔法值

书归正传,这个题中所说的异或运算是什么样子的呢:

操作数 1 1 1 (Decimal)操作数 2 2 2 (Decmial)操作数 1 1 1 (Binary)操作数 2 2 2 (Binary)运算符 (Operator)结果 (Result)
1111^0 (0)
0000^0 (0)
1010^1 (1)
0101^1 (1)
120110^11 (3)

我们可以发现,两位都是 1 1 1 ,异或出来反倒为 0 0 0 , 我们可以把它当成不进位的加法使用。

回到这道题,我们结合样例分析:

邻接矩阵:

$\ $123
1011
2101
3110

这道题就可以作为一个矩阵乘法 + 快速幂解决,不断对 2 2 2 取模,得到当时的矩阵里面二进制数值之中 1 1 1 的个数,最后在根据这个不断地去异或即可。

这里介绍一种东西叫做 bitset ,一个数只占一个 bit 的空间,只能存储 0/1,可以当作上面的二进制矩阵使用。(最关键的是它还支持所有C++自带的二进制运算!! 如 &, |, 还有我们用到的^

代码实现

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, q;
int f[101];
struct node {
	bitset <101> s[101];
} I, a;

inline node operator * (node x, node y) {
	node ret;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
            ret.s[i][j] = ((x.s[i] & y.s[j]).count() & 1);
		}
	}
	return ret;
}
inline node ksm(node dishu, int zhishu) {
	node ret = I;
	while (zhishu) {
		if (zhishu & 1) {
			ret = ret * dishu;
		}
		dishu = dishu * dishu;
		zhishu >>= 1;
	}
	return ret;
}

signed main() {
	ios::sync_with_stdio(0);
	cin >> n >> m >> q;

    for (int i = 0; i <= n; ++i) { // 单位矩阵初始化
        for (int j = 0; j <= n; ++j) {
            I.s[i][j] = (i == j ? 1 : 0);
        }
    }

	for (int i = 1; i <= n; ++i) {
		cin >> f[i];
	}
	for (int i = 1; i <= m; ++i) {
		int u, v;
		cin >> u >> v;
		a.s[u][v] = 1;
		a.s[v][u] = 1;
	}
	
	for (int i = 1; i <= q; ++i) {
		int ssr;
		cin >> ssr;
		
		node dd = ksm(a, ssr); // 求出当时的矩阵
		
		int ans = 0;
		for (int j = 1; j <= n; ++j) {
			ans ^= f[j] * 1ll * dd.s[j][1]; // 求出异或值 
		}
		cout << ans << endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值