Codeforces Round #541 (Div. 2)

A题,数学画图题。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int w1,h1,w2,h2;
int main()
{
	w1 = read(), h1 = read(), w2 = read(), h2 = read();
	cout << h1 * 2 + w1 + 2 + w2 + 2 + h2 * 2+w1-w2 << endl;
	return 0;


B题:
给出n个pair,表示两个段的端点,问i与i+1段的重合部分。
这里直接max(fi-1,si-1)<min(fi,si)判断重合部分就行了。
注意判断一些重合的点。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
const int N = 1e4 + 10;
vector<pir >vec;
int main()
{
	n = read();
	int x, y;
	up(i, 0, n)
	{
		x = read(); y = read();
		vec.push_back(make_pair(x, y));
	}
	ll ans = 1;
	int fi = 0;
	int se = 0;
	up(i, 0, n)
	{
		if (max(fi, se) <=min(vec[i].first, vec[i].second))
		{
			ans += -max(fi, se) + min(vec[i].first, vec[i].second)+1;
		}
		if (fi==se)ans--;
		fi = vec[i].first;
		se = vec[i].second;
	}
	cout << ans << endl;
}

C题 乱七八糟构造题
n个人围成一个群,使得相邻两个人的高度差最大值最小。
肯定是这样做最小 矮—高---矮。具体证明看cf官方题解,给出的是哈密顿的证法。(为什么数据量100?)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
const int N = 105;
int a[N];
int res[N];
int main()
{
	int pos = 0;
	n = read();
	up(i, 0, n)a[i] = read();
	sort(a, a + n);
	int mid = n / 2-1;
	upd(i, 0, mid)
	{
		res[i] = a[pos++];
		res[n - i-1] = a[pos++];
	}
	if (n & 1)res[mid + 1] = a[n - 1];
	up(i, 0, n)cout << res[i] << " ";
	return 0;
}

D题:
给出一个矩阵,给出每行分别于每列的大小关系,为是否存在一组这样的大小关系。
对于大小关系的求解,就可以用拓扑排序来解决。
从小的连一条边到大的,然后判断是否有环。
对于等于号我们缩点,用强连通或者上并查集都是可以的。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, m;
const int N = 1010;
vector<int >grp[2*N];
int pr[2*N];
int val[2*N];
int in[2 * N];
int ans[2 * N];
int vis[2 * N];
set<int>st[N];
char s[N][N];
int op;
void init()
{
	upd(i,1,n+m)
	{
		pr[i] = i;
		val[i] = 1;
	}
}
int find(int x)
{
	return pr[x] == x ? x : pr[x] = find(pr[x]);
}
void unit(int x, int y)
{
	x = find(x), y = find(y);
	if (x == y)return;
	if (val[x] < val[y])swap(x, y);
	pr[y] = x;
	val[x] += val[y];
}
int topo_sort()
{
	vector<int >vec;
	upd(i, 1, n + m)
	{
		if (in[find(i)] == 0) {
			vec.push_back(find(i)); in[find(i)] = -1; ans[find(i)] = 1; vis[find(i)] = true;
		}
	}
	while (!vec.empty())
	{
		int back = vec.back();
		//cout << find(back) << endl;
		vis[find(back)] = true;
		vec.pop_back();
		for (auto k : grp[find(back)])
		{
			//cout << find(k) << endl;
			in[find(k)]--;
			if (in[find(k)] == 0)vec.push_back(find(k)), in[find(k)] = -1, ans[find(k)] = ans[find(back)] + 1;
		}
	}
	upd(i, 1, n + m)if (!vis[find(i)])return -1;
	return 1;
}
int main()
{
	n = read();
	m = read();
	init();
	upd(i, 1, n)
	{
		cin >> s[i]+1;
		bool flag = true;
		upd(j,1, m)
		{
			if (s[i][j] == '=')
			{
				unit(i, j + n);
			}
		}
	}
	upd(i, 1, n)
	{
		upd(j, 1, m)
		{
			if (s[i][j] == '<')grp[find(i)].push_back(find(n+j)),in[find(n+j)]++;
			else if (s[i][j] == '>')grp[find(n+j)].push_back(find(i)),in[find(i)]++;
		}
	}
	if (topo_sort() == -1) {
		cout << "No" << endl;
		return 0;
	}
	cout << "Yes" << endl;
	upd(i, 1, n)
		cout << ans[find(i)] << " ";
	cout << endl;
	upd(i, n + 1, n+m)
		cout << ans[find(i)] << " ";
	return 0;
}

E题 字符串上的dp。
定义字符串的乘法 s*t为 t s[0]t s[1]t s[2] 。。。定义ans为结果串中,连续字母的最长长度。
我们可以发现,一个串的最后结果,只与上一个串有关,而上一个串对答案的贡献只有单个字母,因为被插入了最后一个字符串,所以我们分类讨论一下。
dp[i][j] 表示第i个字符串中,字符j的最长长度。(初始化为1)
然后我们就有假设i+1字符串中,自己就自带了len长度的j个连续字符
dp[i][j]=max(len,dp[i][j])
然后上一个串对于现在这个串之贡献一个,那么我们只需要考虑t的前缀和后缀,因为接在了上个串中。
如果上一个有前缀这个字母的话dp[i][j]=max(prefix+1)有后缀的话(dp[i][j]=max(suffix)
如果t是单串,那么就可以把一段字符给构造出来。而我们这里只需要考虑上一个字符串中最长的该字符就行了。即dp[i-1][j] 的值。
同样第四种情况就是,前缀和后缀一样但不是单串例如aabaa。那么接在a中间时就有
aabaa a aabaa长度更新为prefix+suffix+1.(dp转移状态不够时就多加状态,大多数直奔主题暴力构造dp即可)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
   char ch = getchar(); int x = 0, f = 1;
   while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
   while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
   return x * f;
}
typedef pair<int, int> pir;
int n;
string s;
const int N = 1e5 + 10;
int dp[N][30];
int main()
{
   n = read();
   upd(i, 1, n)
   {
   	cin >> s;
   	int len = s.size();
   	up(j, 0, 26)
   		if (dp[i - 1][j])dp[i][j] = 1;
   	int r = 0, l = 0, pre = 0, suf = 0, flag = 0;
   	for (; r < len;l=r+1,r=l)
   	{
   		int st = s[r] - 'a';
   		while (r < len&&s[l] == s[r+1])r++;
   		dp[i][st] = max(dp[i][st], r - l + 1);
   		if (l == 0)pre = r;
   		if (r == len - 1)suf = l;
   		if (l == 0 && r == len - 1)flag = 1;
   	}
   	int stp = s[0] - 'a';
   	int sts = s[len - 1] - 'a';
   	if (flag&&dp[i-1][stp])dp[i][stp] = max(dp[i][stp], len*(dp[i - 1][stp] + 1) + dp[i - 1][stp]);
   	if (dp[i - 1][stp])dp[i][stp] = max(dp[i][stp], 1 + pre + 1);
   	if (dp[i - 1][sts])dp[i][sts] = max(dp[i][sts], 1 + len - suf);
   	if (stp == sts && dp[i - 1][sts])dp[i][sts] = max(dp[i][sts], 1 + pre + 1 + len - suf);
   }
   int ans = 0;
   up(i, 0, 26)
   	ans = max(ans, dp[n][i]);
   cout << ans << endl;
}

E题
题意:合并区间
很明显就是启发式合并的应用。
(裸的启发式合并)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
const int N = 15e4 + 10;
int pr[N];
int val[N];
set<int >s[N];
int ans[N];
int pos[N];
void init()
{
	upd(i, 1, n)pr[i] = i, val[i] = 1;
	upd(i, 1, n)s[i].insert(i);
}
int find(int x)
{
	return pr[x] == x ? x : pr[x] = find(pr[x]);
}
void unit(int x, int y)
{
	x = find(x);
	y = find(y);
	if (x == y)return;
	if (val[x] < val[y])swap(x, y);
	for (auto k : s[y])
	{
		ans[k] += val[x];
		//pos[ans[k]] = k;
		s[x].insert(k);
	}
	s[y].clear();
	pr[y] = x;
	val[x] += val[y];
}
int main()
{
	n = read();
	int x, y;
	init();
	upd(i, 1, n)ans[i] = 1;
	up(i, 0, n-1)
	{
		x = read(), y = read();
		x = find(x), y = find(y);
		unit(x, y);
	}
	upd(i, 1, n)
	{
		pos[ans[i]] = i;
	}
	upd(i, 1, n)cout << pos[i] <<" ";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值