2020牛客暑期多校训练营(第一场)

F.Infinite String Comparision
题目链接:https://ac.nowcoder.com/acm/contest/5666/F

分析:如果求两个字符串的长度的lcm的话,会爆内存。因此,尝试比较长度的两倍即可,根据周期性定理,如果长度等于(a + b - gcd(a, b)),如果两个字符串没有失配,那么这两个字符串是相等的。(a + b - gcd(a, b) <= min(2 * lena, 2 * lenb))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;
const int N = 100005;

int main()
{
	string a, b;
	while (cin >> a >> b)
	{
		int lena = a.size(), lenb = b.size();

		if (lena > lenb)
		{
			int i = 0;
			for (i = 0; i < lena * 2; ++i)
			{
				char na = a[i % lena];
				char nb = b[i % lenb];
				if (na < nb)
				{
					cout << "<" << endl;
					break;
				}
				else if(na > nb)
				{
					cout << ">" << endl;
					break;
				}
			}
			if (i == 2 * lena) cout << "=" << endl;
		}
		else
		{
			int i = 0;
			for (i = 0; i < lenb * 2; ++i)
			{
				char na = a[i % lena];
				char nb = b[i % lenb];
				if (na < nb)
				{
					cout << "<" << endl;
					break;
				}
				else if (na > nb)
				{
					cout << ">" << endl;
					break;
				}
			}
			if (i == 2 * lenb) cout << "=" << endl;
		}
	}
	
	return 0;
}

H.Minimum-cost Flow(费用流)
题目链接:https://ac.nowcoder.com/acm/contest/5666/H

分析:首先看到分数(frac{ui}{vi}),可以想到用(gcd)化简。可以看到数据范围非常大,如果每次询问都建立一次图跑费用流,那么就会超时。不妨假设(总流量为1),每条边的容量(frac{ui}{vi}),同时乘以(v),那么总流量则为(v),每条边的容量则为(u)。那么当我们跑完费用流后,算出(总费用除以/v),并且使用(gcd)化简,即可得到答案。(每次spfa都会得到一条增广路的费用,同时这条增广路的流量在每条边上都是等流量的),我们算出每条增广路的费用后,用一个前缀和维护费用的前缀和。
(path[a]:下标从0开始,表示第a + 1条增广路的费用)
(sum[a]:下标从1开始,表示前a条增广路的费用)
这些预处理出来的费用是容量为1的时候的费用。我们假设(v = a * u + b(b < u)),表示前a条的增广路的流量为a,第a + 1条增广路的流量为b,那么总的流量则为v,那么答案则为(ans = (sum[a] * u + path[a] * b) / v)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;
using LL = long long;
const int N = 100, M = 55 * 55 * 2;
const LL inf = (1LL << 60);
int h[N], e[M], ne[M], w[M], idx;
//费用
LL cost[M];
//到某个点的费用
LL d[N], incf[N];
int pre[N];
bool st[N];

int n, m;
int s, t;
//最大流和最大费用
LL res, maxflow;

//每条增广路的费用和前缀和
vector<LL> path;
LL sum[N];

LL gcd(LL a, LL b)
{
	return b ? gcd(b, a % b) : a;
}

//z:容量 c:单位费用
void add(int a, int b, int z, int c)
{
	e[idx] = b, w[idx] = z, cost[idx] = c, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, w[idx] = 0, cost[idx] = -c, ne[idx] = h[b], h[b] = idx++;
}

bool spfa()
{
	queue<int> q;
	//求最小费用
	for (int i = s; i <= t; ++i)
		d[i] = inf;
	memset(st, 0, sizeof st);

	q.push(s);
	d[s] = 0, st[s] = true;
	//增广路上各边的最小剩余容量
	incf[s] = inf;

	while (q.size())
	{
		int u = q.front();
		q.pop();
		st[u] = false;
		for (int i = h[u]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (!w[i]) continue;
			if (d[j] > d[u] + cost[i])
			{
				d[j] = d[u] + cost[i];
				incf[j] = min(incf[u], (LL)w[i]);
				pre[j] = i;
				if (!st[j])
				{
					st[j] = true;
					q.push(j);
				}
			}
		}
	}
	if (d[t] == inf) return false;
	return true;
}

void update()
{
	int u = t;
	while (u != s)
	{
		int i = pre[u];
		w[i] -= incf[t];
		w[i ^ 1] += incf[t];
		u = e[i ^ 1];
	}
	//一条增广路的总的单位费用
	path.push_back(d[t]);
	maxflow += incf[t];
	res += d[t] * incf[t];
}

int main()
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		memset(h, -1, sizeof h), idx = 0;
		path.clear();

		s = 1, t = n;
		int a, b, c;
		for (int i = 1; i <= m; ++i)
		{
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, 1, c);
		}

		while (spfa()) update();

		int sz = path.size();
		//增广路费用的前缀和
		for (int i = 1; i <= sz; ++i)
		{
			sum[i] = sum[i - 1] + path[i - 1];
		}

		int q;
		scanf("%d", &q);

		while (q--)
		{
			LL u, v;
			scanf("%lld%lld", &u, &v);

			if (u * sz < v)
				puts("NaN");
			else
			{
				LL a = v / u;
				LL b = v % u;

				LL ans;
				if (b == 0)
					ans = sum[a] * u;
				else
					ans = sum[a] * u + path[a] * b;

				LL down = gcd(ans, v);
				ans /= down;
				v /= down;

				printf("%lld/%lld
", ans, v);
			}
		}
	}

	return 0;
}

J.Easy Integration(找规律)
题目链接:https://ac.nowcoder.com/acm/contest/5666/J

n = 1时, res = 1 / (2 * 3)
n = 2时, res = (1 * 2) / (3 * 4 * 5)
n = 3时, res = (1 * 2 * 3) / (4 * 5 * 6 * 7)

(res = frac{n!}{frac{(2 * n + 1)!}{n!}})

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;
using LL = long long;
const int mod = 998244353;
const int N = 2000005;
int fact[N], infact[N];
int qmi(int a, int k, int p)
{
	int res = 1;
	while (k)
	{
		if (k & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		k >>= 1;
	}
	return res;
}

int main()
{
	fact[0] = infact[0] = 1;
	for (int i = 1; i < N; ++i)
	{
		fact[i] = (LL)fact[i - 1] * i % mod;
		infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
	}

	int n;
	while (cin >> n)
	{
		//int up = n;
		int down = 2 * (n + 1);

		int res = 1;
		res = (LL)res * fact[n] % mod;
		res = (LL)res * res % mod;
		res = (LL)res * 2 * (n + 1) % mod;

		cout << (LL)res * infact[down] % mod << endl;
	}
	
	return 0;
}

原文地址:https://www.cnblogs.com/pixel-Teee/p/13303185.html