牛客练习赛133

A 万年沉睡的宝藏

题意:有一些岛和一些宝藏,都用字符串来描述,会有4个操作:给一个岛加一个宝藏,问这个岛有多少宝藏,某个宝藏是否在这个岛上,有多少岛上有至少一个宝藏。

用map存string和set就行了,注意特判没有这个岛的情况。

点击查看代码
void solve() {
    int q;
    std::cin >> q;
    std::map<std::string, std::set<std::string> > mp;
    while (q -- ) {
    	int op;
    	std::cin >> op;
    	if (op == 1) {
    		std::string s, t;
    		std::cin >> s >> t;
    		mp[s].insert(t);
    	} else if (op == 2) {
    		std::string s;
    		std::cin >> s;
    		int ans = mp.count(s) ? mp[s].size() : 0;
    		std::cout << ans << "\n";
    	} else if (op == 3) {
    		std::string s, t;
    		std::cin >> s >> t;
    		int ans = mp.count(s) ? mp[s].count(t) : 0;
    		std::cout << ans << "\n";
    	} else {
    		std::cout << mp.size() << "\n";
    	}
    }
}

B 完美主义追求者

题意:给你a和b,求a个点的二叉树有多少个本质不同的,对b取模。

猜了一下是a的阶乘个,不会证明。
因为a很大,无法算阶乘,但注意b只有1e6,当a<b时暴力,否则a>=b时因为因子乘了一个b,模数肯定是0.
(赛时写的python,以为要用高精度算阶乘,结果wa了一发,后来发现正确做法后只需要随便改一下就行了,所以还是python代码)

点击查看代码
import math

a, b = map(int, input().split());

if a < b:
	ans = 1
	for i in range(1, a + 1):
		ans = ans * i % b
	print(ans)
else:
	print(0)

C 异或与位移

题意:一个长度位n的数组a,和一个k,a的值在-k + 1到 k - 1之间,m个询问,给你一个二进制数y,它是由一个x变过来的:第i次变化中,如果ai > 0就让x和x左移ai位异或,否则和x右移ai位异或。求这个x。

因为我们知道y,所以我们可以反过来操作,举个例子,对于一个二进制数abc(a, b, c等于0或1), 它左移2位等于110,那么就是c00 ^ abc = 110这是可以求出来abc的,先根据那几个0来确定后面几位,然后根据后面的数确定前面的数。右移一样的思路。 那么我们可以倒退操作找到x。

点击查看代码
void solve() {
    int n, m, k;
    std::cin >> n >> m >> k;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    while (m -- ) {
    	std::string s;
    	std::cin >> s;
    	s = std::string(k - (int)s.size(), '0') + s;
    	bool flag = true;
    	for (int i = n - 1; i >= 0; -- i) {
			std::string t(k, '?');
    		if (a[i] > 0) {
    			for (int j = k - a[i]; j < k; ++ j) {
    				t[j] = s[j];
    			}

    			for (int j = k - a[i] - 1; j >= 0; -- j) {
    				if (t[j + a[i]] == '?') {
    					flag = false;
    					break;
    				}

    				t[j] = ((t[j + a[i]] ^ s[j]) & 1) + '0';
    			}
	    	} else {
	    		for (int j = 0; j < -a[i]; ++ j) {
	    			t[j] = s[j];
	    		}

	    		for (int j = -a[i]; j < k; ++ j) {
	    			if (t[j + a[i]] == '?') {
	    				flag = false;
	    				break;
	    			}

	    			t[j] = ((t[j + a[i]] ^ s[j]) & 1) + '0';
	    		}
	    	}

	    	if (t.find('?') != t.npos) {
	    		flag = false;
	    	}

	    	if (!flag) {
	    		break;
	    	}

    		s = t;
	    	// std::cout << s << "\n";
    	}

    	if (!flag) {
    		std::cout << -1 << "\n";
    		continue;
    	}

    	int p = s.find('1');
    	if (p == s.npos) { 
    		std::cout << "0\n";
    	} else {
    		std::cout << s.substr(p) << "\n";
    	}
    }
}

D 被拒绝在外的打卡

写麻了,每次wa一发后就发现了问题,前前后后de一个小时bug,最后还是没过,感觉应该还是思路的问题。

题意:给你一棵树或者一棵基环树,开始每个点上都有人,每一时刻每个点上的人都同时移动,两个相邻点上的人可以互换位置,问至少要加几个和原有点连接使得可以无限移动下去。如果不需要加点就输出Yes。

看了官方题解后发现思路和解法2差不多,只不过我没想到基环树不要特殊处理,结果自己特判基环树情况搞个基环树dp搞半天没搞出来。
一个点要么在环里面围着这个环跑,要么和一个相邻的点轮流换。那么考虑树的情况,我们从叶子节点开始匹配,因为叶子节点的匹配是固定的,只能和它的父亲匹配。每个点搞完后会有新的叶子,这样搞下去发现某些点没有可以匹配的就ans+1。那么对于基环树的情况为什么也有效,把官方题解贴这里:
链接:https://ac.nowcoder.com/discuss/1450957

对于基环树,我们有两种情况:

  1. 环上的点轮着移动

    这种情况通过上述方式能够匹配出来。

  2. 有一条边不会被匹配

    我们按照上述方式匹配直到环上的一个点,此时将这个点匹配会让环同时减少两条边,那么此时这个图又变成 了一棵树,我们可以继续按照上述方式匹配,直到没有度数为 1 的点。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::vector<int> > adj(n);
    std::vector<int> deg(n);
    for (int i = 0; i < m; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	adj[u].push_back(v);
    	adj[v].push_back(u);
    	++ deg[u]; ++ deg[v];
    }

    if (n == 1) {
    	std::cout << 1 << "\n";
    	return;
    }

    std::queue<int> q;
    for (int i = 0; i < n; ++ i) {
    	if (deg[i] == 1) {
    		q.push(i);
    	}
    }

    int ans = 0;
    std::vector<int> vis(n);
    while (q.size()) {
    	int u = q.front(); q.pop();
    	if (vis[u]) {
    		continue;
    	}

    	vis[u] = 1;

    	bool flag = false;
    	for (auto & v : adj[u]) {
    		if (!vis[v]) {
    			flag = true;
    			vis[v] = 1;
    			for (auto & x : adj[v]) {
    				if (!vis[x] && -- deg[x] == 1) {
    					q.push(x);
    				}
    			}

    			break;
    		}
    	}

    	if (!flag) {
    		++ ans;
    	}
    }

    if (ans) {
    	std::cout << ans << "\n";
    } else {
    	std::cout << "Yes\n";
    }
}

E 斐波那契的压迫

因为卡d所以看了一眼,很明显是线段树,但感觉比较麻烦并且当时没时间了就继续去做d了。
待补

posted @   maburb  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示