Codeforces Round #556 (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 n, m, r;
int main()
{
	n = read();
	m = read();
	r = read();
	int maxx=1e9;
	int x;
	int ans = 0;
	int price;
	up(i, 0, n)
	{
		x = read();
		maxx = min(x, maxx);
	}
	int num = -1;
	up(i, 0, m)
	{
		x = read();
		if (x < maxx)continue;
		num = max(num, x);
	}
	if (~num)
	{
		ans = (r - (r / maxx) * maxx) + (r / maxx) * num;

		cout << ans << endl;
	}
	else cout << r << endl;
	return 0;
}

B题
基础BFS
注意到这里我们每次拥有一个可以放的5格就一定要放。
因为可以直到从上到下,从左到右,如果有空格,那么一定是现在的一个可以放置的去填满这个空格。
所以对于每一个空格,bfs填满就行了。最后扫一遍看能否将整个图填满,也就是贪心。

#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 = 55;
char grp[N][N];
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,-1,1 };
int main()
{
	n = read();
	up(i, 0, n)
	{
		cin >> grp[i];
	}
	up(i, 0, n)
	{
		up(j, 0, n)
		{
			if (grp[i][j] == '#')continue;
			bool flag = true;
			up(k, 0, 4)
			{
				int xx = i + dx[k];
				int yy = j + dy[k];
				if (xx<0 || xx>=n || grp[xx][yy] == '#'||yy<0||yy>=n)
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				grp[i][j] = '#';
				up(k, 0, 4)
				{
					int xx = i + dx[k];
					int yy = j + dy[k];
					grp[xx][yy] = '#';
				}
			}
		}
	}
	up(i, 0, n)
	{
		up(j, 0, n)
		{
			if (grp[i][j] == '.')
			{
			//	cout << "i" << i << 'j' << j << endl;
				cout << "no" << endl;
				return 0;
			}
		}
	}
	cout << "yes" << endl;
	return 0;
}

C题。构造。
我们可以知道的是,素数除了2以外,都是偶数。所以一开始我们放置2,1,凑出奇数。
那么后面一直放2,可以凑出每一个素数,因为奇数加上偶数是奇数。剩下的放置1就行了。
两个1=一个2所以也是能凑出最远的那个素数的。就满足了题意。

#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 = 2e5 + 10;
int a[N];
int cnt = 0;
int main()
{
	n = read();
	int ones=0, twos=0;
	int sum = 0;
	up(i, 0, n)
	{
		a[i] = read();
		if (a[i] == 1)
		{
			ones++;
		}
		else
			twos++;
		sum += a[i];
	}
	if (ones == 0)
		up(i, 0, n)cout << a[i]<<" ";
	else if (twos == 0)up(i, 0, n)cout << a[i]<<" ";
	else {
		cout << "2 1 ";
		twos--, ones--;
		if (twos)
		{
			while (twos--)
			{
				cout << "2 ";
			}
			while (ones--)
				cout << "1 ";
		}
		else
		{
			while (ones--)cout << "1 ";
		}
	}
	return 0;
	
}

D题
看了博客才会。
题目意思就是问是否能在原序列中剖出现在我们需要的这三个串。
我们维护dp[i][j][k]三位dp表示,三个串长度为i,j,k时,在原序列中至少要在那个位置才能被满足。
所以对于每一次询问。如果i的序列长度加了1,就有三种转移方式。
i长度不变,dp[i][j-1][k]+pos=dp[i][j][k]
j长度不变,和k长度不变。(i已经加1了,需要每一次都优先处理,即j,k不变,i-1)

#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, q;
int pos[30];
const int N = 1e5 + 10;
int pre[N][30];
int dp[300][300][300];
int d[5], p[5];
char st[3][300];
char s[N];
int l1, l2, l3;
string op;
void  check(int x,char y)
{
	if (x == 1)
	{
		l1++;
		st[0][l1] = y;
	//	cout << l1 << l2 << endl;
		upd(i, 0, l2)
		{
			upd(j, 0, l3)
			{
				//cout<<pre[dp[l1 - 1][i][j]][st[0][l1] - 'a'];
				dp[l1][i][j] = pre[dp[l1 - 1][i][j]][st[0][l1] - 'a'];
				if (i)dp[l1][i][j] = min(dp[l1][i][j], pre[dp[l1][i - 1][j]][st[1][i] - 'a']);
				if (j)dp[l1][i][j] = min(dp[l1][i][j], pre[dp[l1][i][j - 1]][st[2][j] - 'a']);
			}
		}
	}

	if (x == 2)
	{
		l2++;
		st[1][l2] = y;
		upd(i, 0, l1)
		{
			upd(j, 0, l3)
			{
				dp[i][l2][j] = pre[dp[i][l2-1][j]][st[1][l2] - 'a'];
				if (i)dp[i][l2][j] = min(dp[i][l2][j], pre[dp[i-1][l2][j]][st[0][i] - 'a']);
				if (j)dp[i][l2][j] = min(dp[i][l2][j], pre[dp[i][l2][j - 1]][st[2][j] - 'a']);
			}
		}
	}

	if (x == 3)
	{
		l3++;
		st[2][l3] = y;
		upd(i, 0, l1)
		{
			upd(j, 0, l2)
			{
				dp[i][j][l3] = pre[dp[i][j][l3-1]][st[2][l3] - 'a'];
				if (i)dp[i][j][l3] = min(dp[i][j][l3], pre[dp[i - 1][j][l3]][st[0][i] - 'a']);
				if (j)dp[i][j][l3] = min(dp[i][j][l3], pre[dp[i][j - 1][l3]][st[1][j] - 'a']);
			}
		}
	}
}
int main()
{
	n = read();
	q = read();
	cin >> s+1;
	up(i, 0, 26)pre[n+1][i] = n+1, pos[i] = n+1;
	dwd(i, n , 0)
	{
		up(j, 0, 26)	
		{
			
			pre[i][j] = pos[j];
			if (s[i] - 'a' == j)
			{
				pos[j] = i;
			}
		}
	}
	while (q--)
	{
		cin >> op;
		if (op[0] == '+')
		{
			int a; char b[2];
			a = read(), cin >> b;
			check(a,b[0]);
		//	cout <<"dp"<< dp[l1][l2][l3] << endl;;
			if (dp[l1][l2][l3] <= n)
			{
				cout << "yes" << endl;
			}
			else
				cout << "no" << endl;
			
		}
		else
		{
			int a;
			a = read();
			if (a == 1)l1--;
			else if (a == 2)l2--;
			else l3 -- ;
			if (dp[l1][l2][l3] <= n)
			{
				cout << "yes" << endl;
			}
			else
				cout << "no" << endl;
		}
	}
	return 0;
}

E题
给出中序遍历,求树上最远两点距离。
一开始树状数组维护,发现不行,改用线段树,然后合并区间一堆错误。最后看博客慢慢才看明白究竟该怎么合并。感觉自己树上操作不够熟练。
这里我们运用公式,树上任一点为根节点的时候,都有 h[v]+h[u]-2h[lca(v,u)](树上差分)
所以我们找的就是让这个最大的值。
考虑(=1,)=-1 ,那么h到根的高度就是前缀和。
我们线段树来维护的是整个中序遍历出来的序列。意味着,根节点一定在[l,r ]之间,即[l,r]中深度最小点就是l和r的lca。
我们现在找的就是[l,r]中h[v]+h[u]-2
h[lca[v,u]](l<=v<=u<=r)的最大值。那么让h[v]尽量大,同时维护h[lca[v,u]]小就行了。
我们可以知道这样的区间要么在整个左子树,要么在整个右子树,要么跨界。所以我们分别维护就好了。维护如果选最深点在左区间的时候,h[v]-2*h[lca]的最大值,然后就能跨到右区间了,同理右跨左。
注意左右子树合并的时候,需要计算高度。因为在原来的树中,相当于把右边的序列接到了左子树。
例如(()),右子树))的高度需要加上左子树((的高度2。(合并细节蛮多的,有些细节我还是没懂其实。。留个坑吧)

#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;
const int N = 2e5 + 10;
int n, q;
string s;
struct node
{
	int	height, amx, bmin, lmax, rmax,ans;
	node(int height=0,int amx=0,int bmin=0,int lmax=0,int rmax=0,int ans=0):height(height),amx(amx),bmin(bmin),lmax(lmax),rmax(rmax),ans(ans){}
	node  operator+(const node&a)const
	{
		node temp;
		temp.height = height + a.height;
		temp.amx = max(amx, a.amx+height);
		temp.bmin = min(bmin, a.bmin+height);
		temp.lmax = max(max(lmax, a.lmax-height), amx - 2 * (a.bmin+height));
		temp.rmax = max(max(rmax, a.rmax-height), a.amx-2*bmin+height);
		temp.ans = max(max(ans, a.ans), max(lmax + a.amx + height, a.rmax + amx - height));
		return temp;
	}
}tree[4*N];
void build(int l,int r,int num)
{
	if (l == r)
	{
		int k = s[l-1] == '(' ? 1 : -1;
		tree[num].height = k;
		tree[num].amx = tree[num].bmin = k;
		tree[num].lmax = tree[num].rmax = -k;
		tree[num].ans = 0;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, num << 1);
	build(mid + 1, r, num << 1 | 1);
	tree[num] = tree[num << 1] + tree[num << 1 | 1];
}
void build2(int l, int r, int k, int x)
{
	if (l == r)
	{
		build(l, r, k);
		return;
	}
	int mid = (l + r) >> 1;
	if (x <= mid)build2(l, mid, k << 1, x);
	else build2(mid + 1, r, k << 1 | 1, x);
	tree[k] = tree[k << 1] + tree[k << 1 | 1];
}
void print(int l,int r,int k)
{
	if (l == r) {
		cout << tree[k].ans << endl;
		return;
	}
	int mid = (l + r) >> 1;
	print(l, mid, k<<1);
	print(mid + 1, r, k << 1 | 1);
}
int main()
{
	n = read();
	q = read();
	cin >> s;
	n = 2 * (n - 1);
	build(1, n, 1);
	cout << tree[1].ans << endl;
	//print(1,n,1);
	int x, y;
	while (q--)
	{
		x = read();
		y = read();
		x--, y--;
		swap(s[x], s[y]);
		build2(1, n, 1,x+1);
		build2(1, n, 1, y + 1);
		cout << tree[1].ans << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值