Gravatar
yrtiop
积分:2106
提交:312 / 814

zyf 的题解,写得比我好 QAQ

不难发现,答案为 YES,当且仅当所有点的出度均为 1。

考虑如何维护每个点的出度。

暴力的做法是对于每个点维护两个 set,分别表示当前与之相连/不相连的点,暴力删点加点。如果没有 $t=4$,不难发现总操作次数是 $\mathcal O(n+q)$ 级别的,可以获得 60 pts。

(据说这道题可以通过玄学暴力优化在民间数据拿到满分,毕竟这题的数据并不好造,很难有极限数据)

(然而我考场上尝试玄学暴力乱搞,结果全输出 NO,爆零了 QAQ)

upd:现在还没有出数据,但据说全输出 NO 能有 45 pts?乱搞选手赢麻了。

再次 upd:出数据了,我这种乱搞法居然 50pts,赢麻了,但是 rp-- 了 QAQ。

计算了一下,前 60 pts 暴力,后面全输出 NO,能有 80 pts,已经不比正解低多少了。

这道题的核心就是维护出度为 1 的点数,而有了 $t=4$ 的操作会变得非常棘手,没有任何数据结构可以维护。

一般来说(至少以窝之前打的一场 CF 看来),这种情况可以转向随机化。

考虑哈希。对每个点赋一个独一无二的权值(我采用了类似字符串哈希的构造方式),设第 $i$ 个点点权为 $a_i$,定义 $tot=\sum\limits_{i=1}^n a_i,ans=\sum\limits_{i=1}^n deg_i\times a_i$。

其中 $deg_i$ 表示点 $i$ 的出度。

由于点权都是独一无二的,若 $ans=tot$,那么就有极大的概率满足 $\forall i\in [1,n],deg_i=1$。

$tot$ 可以直接计算,而 $ans$ 的维护也相当简单,单次操作时间复杂度 $\mathcal O(1)$。

总时间复杂度为 $\mathcal O(n)$,目前在 InfOJ 上的民间数据这种方法可以拿到满分。

如果还不保险,还可以多取几个模数或点权。

upd:似乎不用我这样写,把求和改成异或,直接随机权值就完全能过了 /kel


题目3783  [CSP 2022S]星战 AAAAAAAAAAAAAAAAWWWW      11      评论
2022-11-08 10:56:11    
Gravatar
yuan
积分:1083
提交:416 / 672


题目20  [HAOI 2005]破译密文      7      评论
2022-11-07 23:35:17    
Gravatar
李星昊
积分:139
提交:68 / 148
#include<bits/stdc++.h>
using namespace std;
 
string s1,s2;
int a[250],b[250],c[500];
int len; 
int main(){
	freopen("add.in","r",stdin);
	freopen("add.out","w",stdout);
	cin >> s1 >> s2;
 
	
	for (int i = 0; i < s1.size(); i++) {
		a[s1.size() - i - 1] = s1[i] - '0';
	}
	for (int i = 0; i < s2.size(); i++) {
		b[s2.size() - i - 1] = s2[i] - '0';
	}
	
	len = s1.size();
	
	if (s1.size() < s2.size()) {
		len = s2.size();
	}
	
	for (int i = 0; i < len; i++) {
		c[i] = a[i] + b[i];
	}
	
	for (int i = 0; i < len; i++) {
		if (c[i] >= 10) {
			c[i + 1] += c[i] / 10;
			c[i] %= 10;
		}
	}
	
	if (c[len] != 0) {
		len++;
	}
	for (int i = len - 1; i >= 0; i--) {
		cout << c[i];
	}
}
 
//第一步:定义
//第二步:输入
//第三步:将字符串转换成数组
//第四步:相加(中间有进位,详见代码)
//第四步:输出
 

题目37  增强的加法问题 AAAAAAAAAA      3      评论
2022-11-07 10:01:57    
Gravatar
李星昊
积分:139
提交:68 / 148


#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
struct q {
	int a;
	char b[200];
	q()
	{
		a = 0;
	}
	bool operator < (const q &A)const
	{
		return a < A.a;
	}
} Q[51];
int n;
int main()
{
	freopen("nba.in", "r", stdin);
	freopen("nba.out", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%[^0-9]%d", &Q[i].b, &Q[i].a);
		Q[i].b[0] = ' ';
	}
	sort(Q + 1, Q + n + 1);
	for (int i = 1; i <= n; i++)if (Q[i].a != Q[i + 1].a) {
			cout << Q[i].a << ' ' << Q[i].b << endl;
		}
	return 0;
}
//这道题用结构体就行
//第一步:定义结构体
//第二步:输入加排序(详细的见程序)
//第三步:输出


题目482  NBA总冠军 AAAAAAAAAA      3      评论
2022-11-07 09:57:20    
Gravatar
李星昊
积分:139
提交:68 / 148
#include<bits/stdc++.h>
using namespace std;
 
string s1,s2;
int a[250],b[250],c[250];
char f = '+';
int len,p;
int main(){
	freopen("sub.in","r",stdin);
	freopen("sub.out","w",stdout);
	cin >> s1 >> s2;
	if (s2.size() > s1.size() || (s1.size() == s2.size() && s2 > s1)) {
		swap(s1,s2);
		f = '-';
	}
	
	for (int i = 0; i < s1.size(); i++) {
		a[s1.size() - i - 1] = s1[i] - '0';
	}
	for (int i = 0; i < s2.size(); i++) {
		b[s2.size() - i - 1] = s2[i] - '0';
	}
	
	len = s1.size();
	for (int i = 0; i < len; i++) {
		if (a[i] < b[i]) {
			a[i + 1] -= 1;
			a[i] += 10;
		}
		c[i] = a[i] - b[i];
	}
	if (f == '-') cout << f;
	
	for (int i = len - 1; i >= 0; i--) {
		if (c[i] != 0) {
			p = i;
			break;
		}
	}
	
	for (int i = p; i >= 0; i--) cout << c[i];
}

这道题用三个数组就行。

第一步:把输入的字符串转换成数组(因为都是数字)

第二步:相减,不够就借位

第三步:判断是否是负数

第四步:输出


题目38  增强的减法问题 AAAAAAAAAA      3      评论
2022-11-07 09:52:51    
Gravatar
HeSn
积分:1352
提交:234 / 564

本题三种做法。

第一种:直接跑一遍dfs求最大值,期望得分50分。

第二种:折半搜索,map统计去重,最后求最大值。


#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, m, half, a[50], b[50], num1[1 << 21], num2[1 << 21], cnt1, cnt2, ans;
map<int, int> mp, mp2;
int dfs2(int x, int s, int p) {
	if(x == n + 1) {
		if(!mp2[p]) {
			num2[++ cnt2] = p;
		}
		if(s > mp2[p]) {
			mp2[p] = s;
		}
		return 0;
	}
	dfs2(x + 1, s, p);
	dfs2(x + 1, s + b[x], p ^ a[x]);
}
int dfs(int x, int s, int p) {
	if(x == half + 1) {
		if(!mp[p]) {
			num1[++ cnt1] = p;
		}
		if(s > mp[p]) {
			mp[p] = s;
		}
		return 0;
	}
	dfs(x + 1, s, p);
	dfs(x + 1, s + b[x], p ^ a[x]);
	return 0;
}
signed main() {
    freopen("outsci.in", "r", stdin);
    freopen("outsci.out", "w", stdout);
    cin >> n >> m;
    half = n / 2;
    for(int i = 1; i <= n; i ++) {
    	cin >> a[i];
	}
	for(int i = 1; i <= n; i ++) {
		cin >> b[i];
	}
	dfs(1, 0, 0);
//	for(int i = 1; i <= cnt; i ++) {
//		cout << c[i] << ' ' << mp[c[i]] << endl;
//	}
	dfs2(half + 1, 0, 0);
	for(int i = 1; i <= cnt1; i ++) {
		for(int j = 1; j <= cnt2; j ++) {
			if((num1[i] ^ num2[j]) <= m) {
				ans = max(ans, mp[num1[i]] + mp2[num2[j]]);
			}
		}
	}
	cout << ans << endl;
    return 0;
}

第三种 正解(伪):所有大于零的b求和(

这数据是拿脚捏的吗?这都能水过???

真正的正解还没想到QAQ


题目3790  界外科学 WWWWWWWWWWWW      10      评论
2022-11-06 21:22:10