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

A All with Pairs

题目链接
题目大意

在这里插入图片描述
给定n个字符串,字符串s,t的最长相同的前缀后缀为f(s,t)。

大致思路
对所有后缀求hash,用map来存储。然后对一个字符串的每一个前缀求出hash值,对应的map[hash[i]]就是相同后缀数量。但可能出现重复计数的情况。例如aba,后缀aba包含a,计算a是多计数了一次。所以要求出nxt数组,减去重复计数的即可。
完整代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 100000 + 10;
int n,nxt[N*10],num[N*10];
ll ans = 0, mod = 998244353;
string a[N];
map<ull, int>pls;
void getkmp(string a)
{
	int j = -1;
	nxt[0] = -1;
	for (int i = 1; i < a.size(); i++)
	{
		while (j != -1 && a[i] != a[j + 1])j = nxt[j];
		if (a[i] == a[j + 1])j++;
		nxt[i] = j;
	}
}
void Hash(string a)
{
	ull t = 0,base=1;
	for (int i = a.size() - 1; i >= 0; i--)
	{
		t = t + (a[i] - 'a' + 1) * base;
		base *= 2333;
		pls[t]++;
	}
}
void getnum(string a)
{
	ull t = 0;
	for (int i = 0; i < a.size(); i++)
	{
		t = t * 2333 + (a[i] - 'a' + 1);
		num[i] = pls[t];
	}
}
void getans(string a)
{
	for (int i = 0; i < a.size(); i++)
	{
		if (nxt[i] != -1)
		{
			num[nxt[i]] -= num[i];
		}
	}
	for (ll i = 0; i < a.size(); i++)
	{
		ans = (ans + num[i] * (i+1)*(i+1)) % mod;
	}
	
}
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	read(n);
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		Hash(a[i]);
	}
	for (int i = 1; i <= n; i++)
	{
		getnum(a[i]);
		getkmp(a[i]);
		getans(a[i]);
	}
	printf("%lld\n", ans);
	return 0;
}

B Boundary(待补)

C Cover the Tree

题目链接
题目大意
在这里插入图片描述
求一棵树的最小链覆盖,并输出每条链的两端节点编号。

大致思路

是个结论题,最小链覆盖是叶子节点数/2向上取整。比赛的时候我不知道怎么去输出结果,队友写出来了,dfs序将叶子节点放入数组,然后i和i+size/2的点匹配。正确性题解是这样解释的
在这里插入图片描述
完整代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;

int n, head[N], sumline,du[N];
vector<int>pls;
struct line
{
	int nxt, to;
}p[N*10];
void add(int x, int y)
{
	p[++sumline] = line{ head[x],y };
	head[x] = sumline;
}
void dfs(int f, int u)
{
	if (du[u] == 1)pls.push_back(u);
	for (int i = head[u]; i; i = p[i].nxt)
	{
		int to = p[i].to;
		if (to == f)continue;
		dfs(u, to);
	}
}

int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	read(n);
	for (int i = 1; i <= n - 1; i++)
	{
		int x, y;
		read(x), read(y);
		add(x, y), add(y, x);
		du[x]++, du[y]++;
	}
	dfs(0, 1);
	if (pls.size() & 1)
		pls.push_back(1);
	printf("%d\n", pls.size() / 2);
	for (int i = 1; i <= pls.size() / 2; i++)
	{
		printf("%d %d\n", pls[i - 1], pls[i - 1 + pls.size() / 2]);
	}
	return 0;
}

D Duration

题目链接
题目大意

Given two moments on the same day in the form of HH:MM:SS, print the number of seconds between the two moments.

给定两个时间,输出他们之间相差的秒数。
大致思路
将时间转换为总秒数,然后输出即可(签到题)

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
struct node
{
	int h, m, s;
}p[3];
int getnum(node a)
{
	return a.h * 3600 + a.m * 60 + a.s;
}
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	scanf("%02d:%02d:%02d", &p[1].h, &p[1].m, &p[1].s);
	scanf("%02d:%02d:%02d", &p[2].h, &p[2].m, &p[2].s);
	int num1 = getnum(p[1]);
	int num2 = getnum(p[2]);
	printf("%d\n", abs(num1 - num2));
	return 0;
}

E Exclusive OR(待补)

F Fake Maxpooling

题目链接
题目大意

Given a matrix of size n×mn\times mn×m and an integer k{k}k, where Ai,j=lcm(i,j)A_{i,j} = lcm(i, j)Ai,j=lcm(i,j), the least common multiple of i{i}i and j{j}j. You should determine the sum of the maximums among all k×kk\times kk×k submatrices.

大致思路
先O(n*m)求出A数组

	read(n), read(m), read(k);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (!a[i][j])
				for (int k = 1; k * i <= n && k * j <= m; k++)
					a[i*k][j * k] = i * k * j;

然后,利用单调队列来求最大值。最后相加。
完整代码:

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 5000 + 10;
int n, m, k,a[N][N],f[N][N];

int pls[N*2],head,tail;
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	read(n), read(m), read(k);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (!a[i][j])
				for (int k = 1; k * i <= n && k * j <= m; k++)
					a[i*k][j * k] = i * k * j;
	for (int i = 1; i <= n; i++)
	{
		head = tail = 1;
		for (int j = 1; j <= m; j++)
		{
			while (head<tail && a[i][pls[tail-1]] < a[i][j])tail--;
			while (head<tail&& j - pls[head] + 1 > k)head++;
			pls[tail++] = j;
			if (j >= k)
				f[i][j - k + 1] = a[i][pls[head]];
		}
	}
	ll ans = 0;
	
	memset(pls, 0, sizeof(pls));
	for (int j = 1; j <= m; j++)
	{
		head = tail = 1;
		for (int i = 1; i <= n; i++)
		{
			while (head <tail && f[pls[tail-1]][j] < f[i][j])tail--;
			while (head<tail && i - pls[head] + 1 > k)head++;
			pls[tail++] = i;
			if (i >= k)
				f[i - k + 1][j] = f[pls[head]][j],ans+= f[i - k + 1][j];
		}
	}
	printf("%lld\n", ans);
	return 0;
}

比赛的时候直接O(nmlogn)过去了,st表做法:

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 5000 + 10;
int a[N][N], maxm[N][N], n, m, k;
int gcd(int a, int b)
{
	return !b ? a : gcd(b, a % b);
}

int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	ll ans = 0;
	read(n), read(m), read(k);
	for (int i = 1; i <= 5000; i++)
		for (int j = i; j <= 5000; j++)
		{
			a[i][j] = i * j / gcd(i, j);
			a[j][i] = a[i][j];
			maxm[i][j] = a[i][j];
			maxm[j][i] = a[j][i];
		}
	if (k == 1)
	{
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				ans += a[i][j];
		printf("%lld\n", ans);
		return 0;
	}
	
	int lastbase;
	for (int base = 1; (1 << base) <= k; base++)
	{
		int len = (1 << base);
		lastbase = len;
		for (int i = 1; i + len - 1 <= n; i++)
		{
			for (int j = 1; j + len - 1 <= m; j++)
			{
				int maxa = max(maxm[i][j], maxm[i][j + len / 2]);
				int maxb = max(maxm[i + len / 2][j], maxm[i + len / 2][j + len / 2]);
				maxm[i][j] = max(maxa, maxb);
			}
		}
	}
	
	for (int i = 1; i + k - 1 <= n; i++)
		for (int j = 1; j + k - 1 <= m; j++)
		{
			int maxa = max(maxm[i][j], maxm[i][j + k - lastbase]);
			int maxb = max(maxm[i + k - lastbase][j], maxm[i + k - lastbase][j + k - lastbase]);
			maxm[i][j] = max(maxa, maxb);
			ans += maxm[i][j];
		}


	printf("%lld\n", ans);
	return 0;
}

G Greater and Greater

题目链接
题目大意

Given a sequence A{A}A of size n{n}n and a sequence B{B}B of size m{m}m, determine the number of subintervals(called S{S}S) of size m{m}m in A{A}A satisfying ∀i∈{1,2,⋯ ,m},Si≥Bi\forall i \in \{1, 2, \cdots, m\}, S_i \ge B_ii{1,2,,m},SiBi.

对于给定的A数组问有多少个长度为m子数组满足对应的元素均大于等于B[i].

大致思路
将a,b数组排序。用bitset来维护关系,对于b[i],如果bitset[j]为1表示a[j]大于等于b[i].

完整代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
bitset<150010>ans, res;
pair<int, int>a[N], b[N];
int n, m;
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("182.txt", "r", stdin);
#endif // ONLINE_JUDGE
	read(n), read(m);
	for (int i = 1; i <= n; i++)
	{
		int x; read(x);
		a[i] = { x,i };
	}
	for (int i = 1; i <= m; i++)
	{
		int x; read(x);
		b[i] = { x,i };
	}
	sort(a + 1, a + 1 + n, greater<pair<int,int> >());
	sort(b + 1, b + 1 + m, greater<pair<int,int> >());
	int p = 1;
	ans.set();
	for (int i = 1; i <= m; i++)
	{
		while (a[p].first >= b[i].first && p <= n)
			res.set(a[p++].second);
		
		ans &= (res >> (b[i].second - 1));
	}
	printf("%d\n", ans.count());
	return 0;
}

H Happy Triangle(待补)

I Interval(待补)

J Just Shuffle(待补)

K Keyboard Free(待补)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值