Educational Codeforces Round 103 (Rated for Div. 2) (A - E)

A
要想使最大元素最小,只需使得序列a的和最小,然后将最小和尽量平摊给每个数,最大的那个数便是答案。
因为a[i]是正整数,所以至少为1,所以序列a之和是大于等于n的。所以只需找到最小的 x 使得 x * k >= n,x * k便是最小和

AC代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
 
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
 
int dx[4] = {
    
    0, 1, 0, -1};
int dy[4] = {
    
    1, 0, -1, 0}; 
 
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
 
LL n, m, k;
 
int main()
{
    
    
	int T;
	cin >> T;
	while (T --)
	{
    
    
		cin >> n >> k;
		
		LL sum = (n + k - 1) / k * k;
		
		LL res = (sum + n - 1) / n;
		
		cout << res << endl;
	}
	
	return 0;
}

B
(这题只能加,不能减,我就是一个看错题的憨憨)
设 s 为 p 的前缀和
对每个 p[i] 找到最小的 x 使得 100 * p[i] <= x * k,答案就是最大的 max(x, s[i - 1]) - s[i - 1]

AC代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
 
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
 
int dx[4] = {
    
    0, 1, 0, -1};
int dy[4] = {
    
    1, 0, -1, 0}; 
 
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
 
int n, m, k;
LL p[N], s[N];
 
int main()
{
    
    
	int T;
	cin >> T;
	while (T --)
	{
    
    
		cin >> n >> k;
		for (int i = 1; i <= n; i ++)
		{
    
    
			cin >> p[i];
			s[i] = s[i - 1] + p[i];
		}
		
		LL res = 0;
		for (int i = 2; i <= n; i ++)
		{
    
    
			LL x = (p[i] * 100 + k - 1) / k;
			
			res = max(res, x - s[i - 1]);
		}
		
		cout << res << endl;
	}
	
	return 0;
}

C
每个简单圆都有一个右边界,我们可以从 2 ~ n 枚举右边界 (1显然不能为右边界)
设 f[i] 为以第 i 条边为右边界的最大圆长度
当a[i] = b[i] 时 f[i] = c[i] - 1 + 2 (c[i] 是点数,c[i] - 1 才是边数)
否则 就有两种情况:

  1. 直接以第 i - 1 条线为左边界, 长度为: c[i] - 1 + 2 + abs(a[i] - b[i])
  2. 接在以第 i - 1 条线为右边界的圆后面,将 a[i] ~ b[i] 那一节线删去
    则长度为: c[i] - 1 + 2 + f[i - 1] - abs(a[i] - b[i])

两种情况取最大就是 f[i] 的值

AC代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
 
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
 
int dx[4] = {
    
    0, 1, 0, -1};
int dy[4] = {
    
    1, 0, -1, 0}; 
 
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
 
int n, m, k;
LL a[N], b[N], c[N];
LL f[N];
 
int main()
{
    
    	
	int T;
	cin >> T;
	while (T --)
	{
    
    
		cin >> n;
		for (int i = 1; i <= n; i ++)
			scanf("%d", &c[i]);
		for (int i = 1; i <= n; i ++)
			scanf("%d", &a[i]);
		for (int i = 1; i <= n; i ++)
			scanf("%d", &b[i]);
		
		
		LL res = 0;
		f[0] = 0;
		for (int i = 2; i <= n; i ++)
		{
    
    
			if (a[i] == b[i])
				f[i] = c[i] + 1;
			else
				f[i] = max(c[i] + 1 + f[i - 1] - abs(a[i] - b[i]), c[i] + 1 + abs(a[i] - b[i]));
			
			res = max(res, f[i]);
		}
		
		cout << res << endl;
		
	}
	
	return 0;
}

D
可以很轻易的发现,从 i 出发后还能回到 i, 那么从 i 出发能够到达的最多数量就变成了 i 左边能够到达的数量(包括自己) + i 右边能到达的数量(包括自己) - 1。
因为每经过一条边,所有边都要反向,那么实际上每个点所处的情况只有 2 种:
所有边为一开始的情况,所有边为反向后的情况
这时候解法的轮廓就已经出来了,以计算向左能够到达的最多数量为例:
设 f [ i ] [ j ] 是点 i 在起始情况为 j 的情况下能到达的最大数量(j = 0, 1)
如果在情况 j 下,i 能到达 i - 1, f [ i ] [ j ] = f [ i - 1] [ j ^ 1 ] + 1。
如果不能到达,那 f [ i ] [ j ] = 1。

AC代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;

#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second

int dx[4] = {
    
    0, 1, 0, -1};
int dy[4] = {
    
    1, 0, -1, 0}; 

//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const int N = 3e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);

int n, m, k;
int l[N], r[N];
int f_l[N][2], f_r[N][2];

int main()
{
    
    
	//freopen("C:\\Users\\Super Yuxiao Guo\\Desktop\\Code_Place\\Data_Test\\data.in.txt", "r", stdin);
	//freopen("C:\\Users\\Super Yuxiao Guo\\Desktop\\Code_Place\\Data_Test\\data.out.txt", "w", stdout); 
	
	int T;
	cin >> T;
	while (T --)
	{
    
    
		memset(l, 0);
		memset(r, 0);
		
		cin >> n;
		for (int i = 1; i <= n; i ++)
		{
    
    
			char c;
			cin >> c;
			if (c == 'L') l[i] = 1;
			else r[i - 1] = 1;
		}
		
		f_l[0][0] = f_l[0][1] = 1;
		for (int i = 1; i <= n; i ++)
			for (int j = 0; j < 2; j ++)
			{
    
    
				f_l[i][j] = 1;
				if (l[i] ^ j) f_l[i][j] += f_l[i - 1][j ^ 1]; 
			}
		
		f_r[n][0] = f_r[n][1] = 1;
		for (int i = n - 1; i >= 0; i --)
			for (int j = 0; j < 2; j ++)
			{
    
    
				f_r[i][j] = 1;
				if (r[i] ^ j) f_r[i][j] += f_r[i + 1][j ^ 1];
			}
		
		for (int i = 0; i <= n; i ++)
			cout << f_l[i][0] + f_r[i][0] - 1 << ' ';
		cout << endl;
	}
	
	return 0;
}

E
E题题意看了好长时间才看懂,给了 n 个串 和 m 个串,后面 m 个串每个串有一个匹配串编号为 mt,这个匹配串是前 n 个串里的。问前 n 个串是否有一个排列,使得那 m 个串每个串从这排列的第一个开始找,第一个能够成功匹配的串是初始编号为 mt 的那个串。感觉挺绕的。

解法:
当存在 mt 串与对应串不能成功匹配时,那么情况显然不存在。
匹配成功时,因为 mt 为第一个成功匹配的串,那么即使有其它能够与该串成功匹配的串,也应该放在 mt 后面,那么从 mt 向其他能够与该串匹配成功的串连一条有向边,表示 mt 之后才是它,那当出现环了之后就会变成我在我自己后面,这是不存在的情况,所以很明显,当边连完后是一个拓扑图,那就存在排列,否则不存在,然后拓扑的顺序也很明显是一个解。
还有一个问题就是如何去找与该串匹配的串有哪些,这里我用的 trie 树
不知道还有没有其他更好的方法

AC代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;

#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second

int dx[4] = {
    
    0, 1, 0, -1};
int dy[4] = {
    
    1, 0, -1, 0}; 

//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const int N = 1e5 + 10;
const int NN = 2e7;
const int M = 7e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);

int n, m, k;
int a[4 * N];
int h[N], e[NN], ne[NN], idx;
int d[N], id[N], cnt;
bool st[N];

string g[N];
vector<int> v;

int tr[4 * N][27], tot = 1;

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

bool check(string a, string b)
{
    
    
	for (int i = 0; i < k; i ++)
		if (a[i] != b[i] && a[i] != '_' && b[i] != '_')
			return false;
	
	return true;
}

void insert(string s, int x)
{
    
    
	int p = 1;
	for (int i = 0; s[i]; i ++)
	{
    
    
		int ch;
		if (s[i] == '_') ch = 26;
		else ch = s[i] - 'a';
		
		if (tr[p][ch] == 0) tr[p][ch] = ++ tot;
		p = tr[p][ch];
	}
	
	a[p] = x;
}

void search(string s, int p, int now)
{
    
    
	if(now == k)
	{
    
    
		v.push_back(a[p]);
		return ;
	}
	
	char c = s[now];
	if (c == '_')
	{
    
    
		for (int i = 0; i < 27; i ++)
			if (tr[p][i])
			{
    
    
				search(s, tr[p][i], now + 1);
			}
	}
	else
	{
    
    
		if (tr[p][26]) search(s, tr[p][26], now + 1);
		if (tr[p][s[now] - 'a']) search(s, tr[p][s[now] - 'a'], now + 1);
	}
}

void bfs()
{
    
    
	queue<int> q;
	
	for (int i = 1; i <= n; i ++)
		if (!d[i])
		{
    
    
			q.push(i);
		}
	
	cnt = 0;
	while (q.size())
	{
    
    
		int t = q.front();
		q.pop();
		
		id[++ cnt] = t;
		
		for (int i = h[t]; ~i; i = ne[i])
		{
    
    
			int j = e[i];
			if (-- d[j] == 0) q.push(j);
		}
	}
}

int main()
{
    
    
	memset(h, -1);
	
	cin >> n >> m >> k;
	
	for (int i = 1; i <= n; i ++)
	{
    
    
		cin >> g[i];
		
		insert(g[i], i);
	}
	
	bool flag = true;
	for (int i = 1; i <= m; i ++)
	{
    
    
		string s;
		int x;
		cin >> s >> x;
		
		if (!flag) continue;
		
		if (!check(s, g[x])) flag = false;
		else
		{
    
    
			v.clear();
			
			search(s, 1, 0);
			for (int i = 0; i < v.size(); i ++)
				if (v[i] != x)
				{
    
    	
					d[v[i]] ++;
					add(x, v[i]);
				}
		}
	}
	
	bfs();
	if (cnt < n) flag = false;
	
	if (!flag) cout << "NO" << endl;
	else
	{
    
    
		cout << "YES" << endl;
		
		for (int i = 1; i <= n; i ++)
			cout << id[i] << ' ';
		cout << endl;
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45904666/article/details/113409443