【2021夏纪中游记】2021.7.12模拟赛

2021.7.12模拟赛

比赛概括:

\(\mathrm{sum}=40+0+0+5\)

唉。

T1 好元素:

题目大意:

找到 \(a_1+a_2+a_3=a_4\) 的个数(\(1,2,3\) 可以相等)。

思路:

一眼题,用将 \(a_1+a_2+a_3=a_4\) 转移为 \(a_1+a_2=a_4-a_3\),然后 \(\mathcal{O}(n^2)\) 加哈希。

但是不能用 map,否则回超时。

代码:

const int N = 5e3 + 10;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, mod = 25000003, ans;
ll a[N];
int hash[25000005];

inline int Hash(int val, int op = 1)
{
	int x = (val % mod + mod) % mod;
	for (; hash[x] != 1010580540 && hash[x] != val; x = (x + 1) % mod);
	if (op)
		return x;
	hash[x] = val;
	return 0;
}

int main()
{
	freopen("good.in", "r", stdin);
	freopen("good.out", "w", stdout);
	memset (hash, 60, sizeof hash);
	n = Read();
	for (register int i = 1; i <= n; i++)
	{
		a[i] = Read();
		for (register int j = 1; j < i; j++)
			if(hash[Hash(a[i] - a[j])] == a[i] - a[j]) {ans++; break;}
		for (register int j = 1; j <= i; j++)
			if(hash[Hash(a[i] + a[j])] != a[i] + a[j]) Hash(a[i] + a[j], 0);
	}
	printf ("%d\n", ans);
	return 0;
}

T2 最短路径:

题目大意:

在平面直角坐标系内的 \(n\) 个点,选择两条路径使得所有点必须被经过,且 \(b1\) 必在路线一、\(b2\) 必在路线二。

思路:

由于确定了路线一,路线二就也确定了,所以一开始想到的状态是设 \(f_{i,j}\) 表示路线一从 \(j\) 来到 \(i\) 的最小值,但是这么设会导致路线二很难连接。

因此,考虑两个路线一起设,设 \(f_{i,j}\) 表示路线一正着走到 \(i\)、路线二倒着走到 \(j\) 的最小数。则有:

\[\begin{aligned} f_{i,k}&=\min\{f_{i,j}+\mathrm{dis}(j,k)\}\\ f_{k,j}&=\min\{f_{i,j}+\mathrm{dis}(i,k)\} \end{aligned}\]

其中 \(k=\max(i,j)+1\)\(n\) 时要特判处理。

代码:

const int N = 1010;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, b1, b2;
struct point
{
	int x, y, id;
}a[N];

bool cmp (point a, point b)
{
	return a.x < b.x;
}

double f[N][N];

double Dis(int i, int j)
{
	return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) +
	 (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

int main()
{
	freopen("path.in", "r", stdin);
	freopen("path.out", "w", stdout);
	n = Read(), b1 = Read(), b2 = Read(); b1++, b2 ++;
	for (int i = 1; i <= n; i++)
		a[i].x = Read(), a[i].y = Read(), a[i].id = i;
	sort (a + 1, a + 1 + n, cmp);
	a[0] = a[1];
	for (int i = 1; i <= n; i++) 
	{
		if (a[i].id == b1) b1 = a[i].id;
		if (a[i].id == b2) b2 = a[i].id;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			f[i][j] = 1e9;
	f[1][1] = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			int k = max(i, j) + 1;
			if (max(i, j) == n) 
			{
				if (i == n) f[n][n] = min(f[n][n], f[n][j] + Dis(j, n));
				else f[n][n] = min(f[n][n], f[i][n] + Dis(i, n));
				continue;
			}
			if (k != b1) f[i][k] = min(f[i][k], f[i][j] + Dis(j, k));
			if (k != b2) f[k][j] = min(f[k][j], f[i][j] + Dis(i, k));
		}
	printf ("%.2lf\n", f[n][n]);
	return 0;
}

T3 [GDOI2016]最长公共子串:

题目大意:

给两个字符串 \(s,t\)。可对 \(s\) 的一些区间进行任意排列,使得 \(s,t\) 的最长公共子串最大,求其长度。

正文:

难确实难。有一个很显然的性质,有交集的区间就让它们并在一起,使范围缩小到 \(O(n)\) 级。

然后考虑匹配,由于区间内的可以按任意顺序,我们就把区间看作一个整体,匹配就是和 \(t\) 比字母数量。设 \(f_{i,j}\) 表示 \(s\)\(i\) 区间、\(t\)\(j\) 字符开始的最长长度。那么就照上文说的,比字母数量。

得到了 \(f\) 后,就能得到 \(g_{i,j}\) 表示 \(s\)\(i\) 区间开始、\(t\)\(j\) 字符开始的最长长度。

然后随便统计答案。

总结:本题思路以小见大(\(f\rightarrow g\))。

代码:

const int N = 2010, M = 1e5 + 10;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

char s[N], t[N];
int n, m, k;
struct node
{
	int l, r;
	bool operator < (const node &a) const
	{
		return l < a.l;
	}
}a[M];
int num[N][27];
int f[N][N], g[N][N];
int bucket[27];
int tot, ans;

int main()
{
	freopen("lcs.in", "r", stdin);
	freopen("lcs.out", "w", stdout);
	scanf("%s%s", t + 1, s + 1);
	n = strlen(t + 1), m = strlen(s + 1);
	k = Read();
	for (int i = 1; i <= k; i++)
		a[i].l = Read() + 1, a[i].r = Read() + 1;
	for (int i = 1; i <= n; i++)
		a[++k] = (node) {i, i};
	sort (a + 1, a + 1 + k);
	tot = 1;
	for (int i = 2; i <= k; i++)
	{
		if (a[i].l <= a[tot].r) a[tot].r = max(a[tot].r, a[i].r);
		else a[++tot] = a[i];
	}
	k = tot;
	for (int i = 1; i <= k; i++)
		for (int j = a[i].l; j <= a[i].r; j++)
			num[i][s[j] - 'a']++;
	
	for (int i = k; i; i--)
		for (int j = m; j; j--)
		{
			int len = a[i].r - a[i].l + 1, l = j;
			for (; l <= min(m, len + j - 1); l++)
			{
				if (num[i][t[l] - 'a'] == bucket[t[l] - 'a']) break;
				bucket[t[l] - 'a'] ++;
			}
			f[i][j] = l - j;
			if (f[i + 1][l] == a[i + 1].r - a[i + 1].l + 1)
				g[i][j] = f[i][j] + g[i + 1][l];
			else g[i][j] = f[i][j] + f[i + 1][l];
			for (int p = j; p <= l; p++)  // [j,l] 是当前区间绝对可以匹配的,找下一个区间最优匹配 
			{
				if (p != l) bucket[t[p] - 'a'] --;
				if (f[i + 1][p] == a[i + 1].r - a[i + 1].l + 1)
					ans = max(ans, p - j + g[i + 1][p]);
				else ans = max(ans, p - j + f[i + 1][p]);
			}
		}
	printf ("%d\n", ans);
	return 0;
}

T4 Vani和Cl2捉迷藏:

题目大意:

最大独立集板题。

正文:

板题不讲。

代码:

const int N = 210, M = 30010;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, k;

bool G[N][N];

int con[N];
bool vis[N];

bool Hungary(int u)
{
	for (int v = 1; v <= n; v++)
	{
		if (!G[u][v]) continue;
		if (vis[v]) continue;
		vis[v] = 1;
		if (!con[v] || Hungary(con[v]))
		{
			con[v] = u;
			return 1;
		}
	}
	return 0;
}

int main()
{
//	freopen("travel10.in", "r", stdin);
//	freopen(".out", "w", stdout);
	n = Read(), k = Read();
	for (int i = 1, u, v; i <= k; i++)
		u = Read(), v = Read(), G[u][v] = 1;
		
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			if (i != k)
				for (int j = 1; j <= n; j++)
					if (j != i && j != k)
						G[i][j] |= G[i][k] & G[k][j];
	int ans = 0;
	for (int i = 1; i <= n; i++)
	{
		memset(vis, 0, sizeof vis);
		if(Hungary(i)) ans++;
	}
	printf ("%d\n", n - ans);
    return 0;
}
posted @ 2021-07-12 20:48  Jayun  阅读(38)  评论(0编辑  收藏  举报