暑假牛客多校第三场 2023-7-24(A、H、J、D)

A. World Fragments I


算法:构造

做法:x中某一个数位选一个数,这个数有可能是0或者是1。求x变到y的最小数,这个数有可能是负数,要取绝对值。
注意如果x0,那么从x中取的数就只有0了,除非y也等于0,否则输出-1

code
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
#define fir first
#define sec second
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<double, double> PDD;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

const int N = 1000010;

void solve()
{
	LL ans = 0, a = 0, b = 0;
	LL two = 1;
	string x, y;
	cin >> x >> y;
	reverse(x.begin(), x.end()), reverse(y.begin(), y.end());

	if (x.size() == 1 && x[0] == '0' && (y[0] == '1' || y.size() > 1))
	{
		cout << -1 << endl;
		return;
	}

	for (int i = 0; i < x.size(); i++)
	{
		if (x[i] == '1')a += two;
		two = 2 * two;
	}

	two = 1;
	for (int i = 0; i < y.size(); i++)
	{
		if (y[i] == '1')b += two;
		two = 2 * two;
	}

	cout << abs(a - b) << endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	solve();

	return 0;
}

 

H. Until the Blue Moon Rises


算法:歌德巴赫猜想
1.哥德巴赫猜想的现代陈述为:任一大于5的整数都可写成三个质数之和。
2.强哥德巴赫猜想(强哥猜):即任一大于2的偶数都可写成两个质数之和。(未被证明,但是同时也没有被推翻,即在本体的范围内强哥猜成立)
3.弱哥德巴赫猜想(弱哥猜): 任何一个大于5的奇数都能被表示成三个奇质数的和。(一个质数可以被多次使用)(已经被证明)

做法:
首先如果 \(n = 1\) 时,如果单独这个数是质数则对,否则错。

\(n = 2\) 时,当两个数的和为偶数且大于等于4,则对,否则错。当两个数的和为奇数时,由于奇数必定由偶数加上奇数组合而成。所以这两个数必定有一个数是偶数,有一个是奇数。先考虑偶数,由于2是偶数中唯一 一个质数,所以偶数必定需要为2,那么奇数就为总和减去2,我们再判断这个总和是不是为质数就可以了。

\(n = 3\) 时,首先我们要保证所有数的总和要大于等于 \(2 * n\),因为最小的质数是2,当所有数都是2时才能出现全部是质数的情况。在这个前提下,我们把所有数都变为2,那么总和减去 \(2 * n\) 即为剩下的数,我们设为 \(x\)。如果 \(x\)偶数,我们可以全部都加到数组的一个数上,即为 \(2 + x\),结果设为 \(y\)\(y\) 必然也是偶数。我们在找数组中的一个数,由于数组的数都是2,那么 \(2 + y\) 也必然是偶数,且大于4,可以分解成两个质数。如果 \(x\)奇数,那么我们把奇数的1移到数组的一个数上,3也为质数。\(x\) 变为了偶数。这时情况和上面 \(x\) 是偶数的情况一样,必定能得到数组中的数都为质数。

借鉴博客

code
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
#define fir first
#define sec second
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<double, double> PDD;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

const int N = 1010;

LL n;
LL w[N];

bool is_prime(LL x)
{
	if (x == 1)return false;

	for (LL i = 2; i <= x / i; i++)
	{
		if (x % i == 0)
			return false;
	}
	return true;
}

void solve()
{
	LL sum = 0;
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> w[i], sum += w[i];

	if (n == 1 && is_prime(w[1]))
	{
		cout << "Yes" << endl;
		return;
	}
	else if(n == 1 && !is_prime(w[1]))
	{
		cout << "No" << endl;
		return;
	}

	if (n == 2 && sum % 2 == 0)
	{
		if (sum >= 4)cout << "YES" << endl;
		else cout << "No" << endl;
		return;
	}
	else if (n == 2 && sum % 2 != 0)
	{
		if (is_prime(sum - 2))cout << "Yes" << endl;
		else cout << "No" << endl;
		return;
	}

	if (sum >= n * 2)cout << "Yes" << endl;
	else cout << "No" << endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	solve();

	return 0;
}

 

J. Fine Logic


算法:拓扑排序

做法:先对图跑一边拓扑排序,如果拓扑排序最终排序的节点小于n,那么这个图中必定有环。有环就从1 - n正着输出一便和倒着输出一便。无环就输出其拓扑排序的结果。说一下为什么能正着输出一便和倒着输出一遍,对于图中的每一对节点,我们选任一一对节点,设为uvu != v)。u > v时,在正着输出时必有<v, u>,倒着输出必有<u, v>v > u时,正着输出时必有<u, v>,倒着输出时必有<v, u>。扩展到每一对节点,这个说法均成立,因此倒着输出一便和正着输出一便是没错的。

code
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
#define fir first
#define sec second
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<double, double> PDD;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

const int N = 1000010;

int n, m;
int h[N], e[N], ne[N], w[N], idx;
int qq[N], du[N], hh, tt;

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool topsort()
{
	hh = 0, tt = -1;
	for (int i = 1; i <= n; i++)
	{
		if (du[i] == 0)
			qq[++tt] = i;
	}

	while (hh <= tt)
	{
		int t = qq[hh++];

		for (int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			du[j]--;
			if (du[j] == 0)qq[++tt] = j;
		}
	}

	return tt == n - 1;
}

void solve()
{
	cin >> n >> m;
	memset(h, -1, sizeof(h));
	for (int i = 0; i < m; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
		du[b]++;
	}

	if (!topsort())
	{
		cout << 2 << endl;
		for (int i = 1; i <= n; i++)cout << i << ' ';
		cout << endl;
		for (int i = n; i >= 1; i--)cout << i << ' ';
	}
	else
	{
		cout << 1 << endl;
		for (int i = 0; i <= tt; i++)cout << qq[i] << ' ';
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	solve();

	return 0;
}

 

D. Ama no Jaku


算法:构造

做法:
\(~~~\)我们知道如果矩阵所有都为01,那么操作为0。我们假设第一行中某一位为1,那么第一列的所有数就都为1,那么列最大值就是都为11111...的串,那么矩阵就都为1
\(~~~\)若第一行没有1,那么列的最大值也应都为00000...的串。
\(~~~\)若矩阵中某一位有1,那么列依照题意一定有11111...的串。
\(~~~\)因此我们所要的矩阵必须是全为0或全为1
\(~~~\)那么什么情况下可以构造出全为0或全为1的矩阵呢?答案是每一行或列都与第一行或列相同或与第一行或列的取反的串相同。没有这种情况就不可能构造出题目所要求的矩阵。假设我们用行来构造正确的矩阵且每行都符合上述的情况,那么每一行要么是与第一行相同的串要么是与第一行取反相同的串。令与第一行相同的串为r且其出现次数为a,取反的为ur且其出现次数为b。再令r1出现的次数为one1ur1出现的次数为one2。因此最小值的答案为$$ ans = min(b+min(one1, n - one1), a+min(one2, n - one2)$$
\(min\) 中的第一部分是如果把第一行取反的串都变为第一行的串(对应b)再加上第一含的串中1变为0的次数与0变为1的次数的最小值(对应min(one1, n - one1))。接下来就是列的情况,我想你应该懂了。

code
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
#define fir first
#define sec second
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<double, double> PDD;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

const int N = 2010;

int n, m;
vector<string> w(N);

string rev(string s)
{
	for (int i = 0; i < s.size() ; i++)
	{
		if (s[i] == '0')s[i] = '1';
		else s[i] = '0';
	}
	return s;
}

int count(string s)
{
	int cnt = 0;
	for (int i = 0; i < s.size(); i++)
		if (s[i] == '1')cnt++;
	return cnt;
}

void solve()
{
	int one = 0, zero = 0, ans = 1e9;
	string r, ur, c, uc;
	vector<string> ww;
	cin >> n;
	for (int i = 0; i < n; i++)cin >> w[i];

	for (int j = 0; j < n; j++)
	{
		string s = "";
		for (int i = 0; i < n; i++)
		{
			s += w[i][j];
			if (w[i][j] == '0')zero++;
			else one++;
		}
		ww.push_back(s);
	}

	if (one == n * n || zero == n * n)
	{
		cout << 0 << endl;
		return;
	}

	int a = 0, b = 0;
	r = w[0], ur = rev(w[0]); 
	int one1 = count(w[0]), one2 = count(ur);
	for (int i = 0; i < n; i++)
	{
		if (w[i] != r && w[i] != ur)break;
		else if (w[i] == r)a++;
		else if (w[i] == ur)b++;
	}

	if (a + b == n)ans = min(b + min(one1, n - one1), a + min(one2, n - one2));

	a = 0, b = 0;
	c = ww[0], uc = rev(ww[0]);
	one1 = count(c), one2 = count(uc);
	for (int i = 0; i < n; i++)
	{
		if (ww[i] != c && ww[i] != uc)break;
		else if (ww[i] == c)a++;
		else if (ww[i] == uc)b++;
	}
	
	if (a + b == n)ans = min(ans, min(b + min(one1, n - one1), a + min(one2, n - one2)));

	if (ans == 1e9)cout << -1 << endl;
	else cout << ans << endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	solve();

	return 0;
}
posted @ 2023-07-25 13:21  dkdklcx  阅读(130)  评论(0)    收藏  举报