codeforces:从第1场开始的刷题记录:记录每场参加的cf

目前:

1,2,3,edu134,818,819

1.不做几何和2600以上的题:

Dashboard - Codeforces Beta Round #1 - Codeforces

1A:这道题我们就贪心就完了:我们尽可能将超出范围的aXa数量变小:可以画个图来理解理解

#include<iostream>
using namespace std;
long long n, m, a;
int main()
{
	long long ans1, ans2;
	cin >> n >> m >> a;
	cout<<(n+a-1)/a*(m+a-1)/a;
}

1B:这道题认真看的话其实就是一个26进制而已:

写法上有些不同 要注意的点在于此时的假如一个数%26=0 代表此时最后位为z 该数/=26后还要-1

/*
1.26 进制
*/
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define int long long
const int maxn = 3e5 + 10;
string s;
void solve()
{
	cin >> s;
	int ok = 0;
	int len = s.length();
	int op = 0;//用来判断哪种形式的
	if (s[0] == 'R')
	{
		
		for (int i = 1; i < len; i++)
		{
			if ('0' <= s[i] && s[i] <= '9')
			{
				continue;
			}
			else
			{
				if (s[i] == 'C')
				{
					ok = i;
					break;
				}
				else
				{
					ok = 0;
					break;
				}
			}
		}
		if (ok != 1 && ok != 0)
		{
			op = 1;
		}
		else
		{
			op = 2;
		}
	}
	else
		op = 2;
	if (op == 1)
	{
		int ok1 = 0;
		for (int i =ok+1; i <len; i++)
		{
			ok1 = 10 * ok1 + (s[i] - '0');
		}
		string s1;
		int len1 = 0;
		while (ok1)
		{
			len1++;
			int now = ok1 %26;
			char s2 = ('A' +now-1);
			ok1 /= 26;
			if (now == 0)
				ok1--;
			if (s2 == 'A' - 1)
				s2 = 'Z';
			s1.push_back(s2);
		}
		for (int i = len1 - 1; i >=0; i--)
			cout << s1[i];
		for (int i = 1; i < ok; i++)
			cout << s[i];
		cout << endl;
	}
	else
	{
		int ok1 = 0;
		int op1;
		for (int i = 0; i < len; i++)
		{
			if (s[i] >= '0'&&s[i] <= '9')
			{	
				op1 = i;
				break;
		}
            else
			{
				ok1 = 26 * ok1 + s[i] - 'A' + 1;
			}
		}
		cout << "R";
		for (int i = op1; i < len; i++)
			cout << s[i];
		cout << "C";
		cout << ok1 << endl;
	}
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
		solve();
}

 Dashboard - Codeforces Beta Round #2 - Codeforces

2A:

这道题的注意点在于我们要维护的是所有处理完的数 而不是中途的最大值:

写法在于我们此时先记录一下过程 并维护每个人的最后结果数字 然后我们找到此时的最大值

之后再按这个方式来维护一下过程 假如找到此时和大于最大值的第一个人 就将其输出:

本质为模拟题:

#include<bits/stdc++.h>
using namespace std;
#define int long long
map<string, int> mp, mpp;
int n, a[100001], maxn =0;
string s[100001], s1;
signed main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i] >> a[i];
		mp[s[i]] += a[i];//记录数值
	}
	for (int i = 1; i <= n; i++)
	{
		maxn = max(maxn, mp[s[i]]);//取最大
	}
	for (int i = 1; i <= n; i++)//谁先到达maxn的就取谁
	{
		mpp[s[i]] += a[i];
		if (mp[s[i]] == maxn && mpp[s[i]] >= maxn)
		{
			s1 = s[i];
			break;
		}
	}
	cout << s1;
	return 0;
}

2B:

这道题的最重要的一个点在于我10=2*5 即 10 只能是由2*5变来的 所以一条路上最小的0个数是由该路上min(num(2),num(5))来决定的 而这个求最小的一般是利用dp来转移的

同时要注意的一点在于假如我们存在0这个数 那么可以发现此时 我们只要ans>1 我们都可以强制让其经过0 使其ans=1

关于输出的话 就bfs就好了

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int maxn = 1e3 + 10;
int dp1[maxn][maxn];
int dp2[maxn][maxn];
int a[maxn][maxn];
int b[maxn][maxn], c[maxn][maxn];
void dfs(int x, int y, int k)//k代表此时我要以
{
	//cout << x << ' ' << y << endl;
	if (k == 2)
	{
		if (x == 1 && y == 1)
			return;
		if (x != 1 && dp1[x - 1][y] + b[x][y] == dp1[x][y])
		{
			dfs(x - 1, y, k);
			cout << 'D';
		}
		else if(y!=1&&dp1[x][y-1]+b[x][y]==dp1[x][y])
		{
			dfs(x, y - 1,k);
			cout << "R";
		}
		
	}
	else
	{
		if (x == 1 && y == 1)
			return;
		if (x != 1 && dp2[x - 1][y] + c[x][y] == dp2[x][y])
		{
			dfs(x - 1, y, k);
			cout << 'D';
		}
		else if (y != 1 && dp2[x][y - 1] + c[x][y] == dp2[x][y])
		{
			dfs(x, y - 1, k);
			cout << "R";
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	int ok = 0;	
	int idx, idy;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> a[i][j];
			int m = a[i][j];
			if (a[i][j] == 0)
			{
				ok = 1;	
				idx = j, idy = j;
			}
			while (a[i][j]%2==0&&a[i][j]!=0)
			{
				b[i][j]++;
				a[i][j] /= 2;
			}
			while (m%5==0&&m!=0)
			{
				c[i][j]++;
				m /= 5;
			}
		}
	}
	memset(dp1, 0x3f, sizeof dp1);
	memset(dp2, 0x3f, sizeof dp2);
	dp1[1][1] = 0;
	dp2[1][1] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (i != 1) {
				dp1[i][j] = dp1[i - 1][j];
				dp2[i][j] = dp2[i - 1][j];
			}
			if (j != 1)
			{
				dp1[i][j] = min(dp1[i][j], dp1[i][j - 1]);
				dp2[i][j] = min(dp2[i][j], dp2[i][j - 1] );
			}
			dp1[i][j] += b[i][j];
			dp2[i][j] += c[i][j];
		}
	}
	int ans = min(dp1[n][n], dp2[n][n]);
	if (ans > 1 && ok)
	{
		cout << 1 << endl;
			for (int i = 1; i < idx; i++)
			{
				cout << "R";
			}
			for (int i = 1; i < n; i++)
				cout << "D";
			for (int i = idx; i < n; i++)
				cout << "R";
			return 0;
		
	}
	cout << ans<< endl;
	if (ans == dp1[n][n])//代表此时是以2为标准
	{
		dfs(n, n, 2);
	}
	else
	{
		dfs(n, n, 5);
	}
}

2C几何

Dashboard - Codeforces Beta Round #3 - Codeforces

3A:

这道题的关键在于组合 :
我们举个例子来说明:假如此时从起点到终点要 向右5 向上6 我们可以将向上和向右维护到一起 这样的话我们此时 右上=min(右,上) 然后还有一步向上是无法被抵消的 所以此时最短要6步

类似这样的思路 我们模拟就好了:

#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
#define int long long
string s1, s2;
signed main()
{
	cin >> s1 >> s2;
	int beginx = s1[1] - '0';
	int beginy = s1[0] - 'a' + 1;
	int endx = s2[1] - '0';
	int endy = s2[0] - 'a' + 1;
	if (beginx < endx)
	{
		if (beginy < endy)
		{
			int minnr = abs(endy - beginy);
			int minnu = abs(endx - beginx);
			int ans = max(minnr, minnu);
			cout << ans << endl;
			for (int i = 1; i <=min(minnr, minnu);i++)
			{
				cout << "RU" << endl;
			}
			for (int i = min(minnr, minnu) + 1; i <= ans; i++)
			{
				if (minnr > minnu)
				{
					cout << "R" << endl;
				}
				else
					cout << "U" << endl;
			}
		}
		else if(beginy>=endy)
		{
			int minnl = abs(endy - beginy);
			int minnu = abs(endx - beginx);
			int ans = max(minnl, minnu);
			cout << ans << endl;
			for (int i = 1; i <= min(minnl, minnu); i++)
			{
				cout << "LU" << endl;
			}
			for (int i = min(minnl, minnu) + 1; i <= ans; i++)
			{
				if (minnl > minnu)
				{
					cout << "L" << endl;
				}
				else
					cout << "U" << endl;
			}
		}
	}
	else
	{
		if (beginy < endy)
		{
			int minnr = abs(endy - beginy);
			int minnu = abs(endx - beginx);
			int ans = max(minnr, minnu);

			cout << ans << endl;
			for (int i = 1; i <= min(minnr, minnu); i++)
			{
				cout << "RD" << endl;
			}
			for (int i = min(minnr, minnu) + 1; i <= ans; i++)
			{
				if (minnr > minnu)
				{
					cout << "R" << endl;
				}
				else
					cout << "D" << endl;
			}
		}
		else if (beginy >= endy)
		{
			int minnl = abs(endy - beginy);
			int minnu = abs(endx - beginx);
			int ans = max(minnl, minnu);
			cout << ans << endl;
			for (int i = 1; i <= min(minnl, minnu); i++)
			{
				cout << "LD" << endl;
			}
			for (int i = min(minnl, minnu) + 1; i <= ans; i++)
			{
				if (minnl > minnu)
				{
					cout << "L" << endl;
				}
				else
					cout << "D" << endl;
			}
		}
	}
}

3B:对于这道题 本来我是想直接贪心的 就类似于01背包问题时 我们都学过的错误写法 可是由于这玩意基本来说就是错误的所以没有写:

正解: 我们可以发现此时的体积就两种情况 这样划分一定有什么用处 由于我们此时最后的体积划分一定是 1 1 1  1 2 1 1 这类写法 所以我们可以枚举我们此时选择多少个1 然后表示(因为此时我们将背包尽可能填满)此时我们选择多少个2就可以直接算出来了 根据贪心来想的话此时我们可以发现 我们从大到小排 维护一个sum 接下来就好写了:

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int sum1[maxn], sum2[maxn];
struct node
{
	int id, x;
	inline bool operator<(const node&m)const
	{
		return x > m.x;
	}
}po1[maxn], po2[maxn];
int ans = 0;
signed main()
{
	int n, k;
	cin >> n >> k;
	int cnt1 = 0, cnt2 = 0;
	for (int i = 1; i <= n; i++)
	{
		int o, l;
		cin >> o >> l;
		if (o == 1)
		{
			po1[++cnt1].id = i, po1[cnt1].x = l;
		}
		else
		{
			po2[++cnt2].id = i, po2[cnt2].x = l;
		}
	}
	sort(po1 + 1, po1 + 1 + cnt1);
	sort(po2 + 1, po2 + 1 + cnt2);
	for (int i = 1; i <= cnt1; i++)
	{
		sum1[i] = sum1[i - 1] + po1[i].x;
	}
	for (int i = 1; i <= cnt2; i++)
	{
		sum2[i] = sum2[i - 1] + po2[i].x;
	}
	int id1=0, id2=0;
	for (int i = 0; i <= cnt1; i++)
	{
		int nowans = sum1[i];
		int now = k - i;
		if (now < 0)
			break;
		int idx;
		if (now/2<=cnt2)
		{		nowans += sum2[now/2];
		idx = now / 2;	
		}
        else
		{
			nowans += sum2[cnt2];
			idx = cnt2;
		}
		if (nowans>ans)
		{
			ans = nowans;
			id1 = i;
			id2 = idx;
		}
	}
	cout << ans << endl;
	for (int i = 1; i <= id1; i++)
	{
		cout << po1[i].id << ' ';
	}
	for (int i = 1; i <= id2; i++)
	{
		cout << po2[i].id << ' ';
	}
}

 3C:这道题说了一大堆就是一个判断题而已 我们几个if就可以搞定了‘

#include<iostream>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
int main() {
	map<char, int> qipan;
	string chess[3];
	int sflag = 0, fflag = 0;
	for (int i = 0; i < 3; i++) {
		cin >> chess[i];//first 玩家为X     second 玩家为0     空地为 . 
		qipan[chess[i][0]]++;
		qipan[chess[i][1]]++;
		qipan[chess[i][2]]++;
	}
	if (qipan['X'] < qipan['0'] || qipan['0'] < qipan['X'] - 1) {
		cout << "illegal";
		return 0;
	}
	if (chess[0][0] == chess[0][1] && chess[0][1] == chess[0][2] && chess[0][0] != '.') {
		if (chess[0][0] == '0') sflag = 1;
		if (chess[0][0] == 'X') fflag = 1;
	}
	if (chess[1][0] == chess[1][1] && chess[1][1] == chess[1][2] && chess[1][0] != '.') {
		if (chess[1][0] == '0') sflag = 1;
		if (chess[1][0] == 'X') fflag = 1;
	}
	if (chess[2][0] == chess[2][1] && chess[2][1] == chess[2][2] && chess[2][0] != '.') {
		if (chess[2][0] == '0') sflag = 1;
		if (chess[2][0] == 'X') fflag = 1;
	}
	if (chess[0][0] == chess[1][0] && chess[1][0] == chess[2][0] && chess[0][0] != '.') {
		if (chess[0][0] == '0') sflag = 1;
		if (chess[0][0] == 'X') fflag = 1;
	}
	if (chess[0][1] == chess[1][1] && chess[1][1] == chess[2][1] && chess[0][1] != '.') {
		if (chess[0][1] == '0') sflag = 1;
		if (chess[0][1] == 'X') fflag = 1;
	}
	if (chess[0][2] == chess[1][2] && chess[1][2] == chess[2][2] && chess[0][2] != '.') {
		if (chess[0][2] == '0') sflag = 1;
		if (chess[0][2] == 'X') fflag = 1;
	}
	if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[0][0] != '.') {
		if (chess[0][0] == '0') sflag = 1;
		if (chess[0][0] == 'X') fflag = 1;
	}
	if (chess[0][2] == chess[1][1] && chess[1][1] == chess[2][0] && chess[0][2] != '.') {
		if (chess[0][2] == '0') sflag = 1;
		if (chess[0][2] == 'X') fflag = 1;
	}
	if (sflag == 1 && fflag == 1 || (sflag == 1 && qipan['X'] > qipan['0']) || (fflag == 1 && qipan['X'] == qipan['0'])) {
		cout << "illegal";
		return 0;
	}
	if (sflag == 1) {
		cout << "the second player won";
		return 0;
	}
	if (fflag == 1) {
		cout << "the first player won";
		return 0;
	}
	if (qipan['X'] == qipan['0'] && qipan['.'] != 0) {
		cout << "first";
		return 0;
	}
	if (qipan['X'] > qipan['0'] && qipan['.'] != 0) {
		cout << "second";
		return 0;
	}
	cout << "draw";
	return 0;
}

 3D:这道题我本来是想利用dp[i][j]代表前i个数中sum为j的最小代价来维护的 可是这样写的话0(n^2) 不太可能 我看了答案 他的话就是贪心的写法 :

 首先对于这种?填左或则右的类型 我们比较常见的写法都是先全填)然后再进行维护 后面有一次比赛好像也考了类似的问题:

所以我们假设此时全部填)然后对一个位置进行考虑 :假如此时位置(<)代表 此时(少了 我们必须将前面的一个)-》( 所以此时我们维护一个优先队列维护我们此时变化的值 取其中最大的 

然后就是判断是否合法了;

最后注意特判一下)???( 这类情况就好了:

#include<queue>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 1e5 + 10;
struct node
{
	int data;
	int id;
	bool operator<(const node&m)const
	{
		return data > m.data;
	}
}t;
priority_queue<node>q;
string s;
signed main()
{
	int cnt = 0;
	int ans = 0;
	int a, b;
	cin >> s;
	for (int i = 0; i < s.length(); i++)
	{
		if (s[i] == '(')
			cnt++;
		else
		{
			cnt--;
			if (s[i] == '?')
			{
				cin >> a >> b;
				t.data = a - b;
				t.id = i;
				q.push(t);
				s[i] = ')';
				ans += b;
			}
		}
	   while(cnt < 0)
		{
			if (q.empty())
			{
				ans = -1;
				break;
			}
			if (ans != -1)
			{
				cnt += 2;
				t = q.top();
				q.pop();
				s[t.id] = '(';
				ans += t.data;
			}
		}
	}
	if (s[0] == ')' || s[s.length() - 1] == '(')
		ans = -1;
	if (cnt)
	{
		ans = -1;
	}
	cout << ans << endl;
	if (ans != -1)
	{
		cout << s;
	}
}





Dashboard - Educational Codeforces Round 134 (Rated for Div. 2) - Codeforces

A:





Dashboard - Codeforces Round #818 (Div. 2) - Codeforces

A:题中lcm/gcd=a*b/(gcd(a,b))^2 可以转化为 此时两个互质的数相乘 <=3 所以此时 1*1,2*1,1*2,3*1,1*3

所以答案为:n+2*(n/2+n/3)

B:此时我们可以发现假如没有r,c的话 我们只要 i%k==j%k 就好了 就是k的循环 当此时存在r,c的话 我们考虑将这一行给提前维护后输出 或者 利用 ((i-r)%k+k)%k==((j-c)%k+k)%k

以(r,c)为中心扩展对角线就好了

C:此时我们可以发现a数组可以无限变大 但最后维护的数组有一个前提:a[i]<a[i+1]+1(或者没有变和之前的一样)

假如b数组中存在b[i]>b[i+1]+1 此时必须要求 b[i]==a[i]即本来就是这个类型

还要考虑之前是否存在a[i]<b[i]的情况

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int n, k;
int a[maxn], b[maxn];
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++)cin >> b[i];
	b[0] = b[n]; a[0] = a[n];
	for (int i = 1; i <= n; i++)
	{
		if (a[i%n] > b[i%n] || (a[i%n] != b[i%n] && b[i%n] > b[i%n + 1] + 1))
		{
			cout << "NO"<<endl;
			return;
		}
	}
	cout << "YES" << endl;
	return;
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
		solve();
}

D:本来看成最小号为多少号 结果不是:

我们考虑最后均为左边获胜 假如我们转移一次 此时到根节点失败次数为1 的话可以胜利 同理 转移k次  到达根节点失败次数为k的人可以胜利 因为每个人到根节点均有n次 其中k次为负的人数为C(n,k) 所以我们利用组合数求和一下  说人话就是 n次比赛中选择k次失败的种类

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;
int fact[maxn], invfact[maxn];
int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1)
		{
			res = res * a%mod;
		}
		b >>= 1;
		a = a * a%mod;
	}
	return res;
}
void init() {
	fact[0] = invfact[0] = 1;
	for (int i = 1; i < maxn; i++)
		fact[i] = fact[i - 1] * i%mod;
	invfact[maxn - 1] = qpow(fact[maxn - 1], mod - 2);
	for (int i = maxn - 2; i; i--)
		invfact[i] = invfact[i + 1] * (i + 1) % mod;
}
int q_mul(int a, int b) {
	a %= mod; b %= mod;
	int ans = 0;
	while (b) {
		if (b & 1)
			ans = (ans + a) % mod;
		a = (a + a) % mod;
		b >>= 1;
	}
	return ans % mod;
}
int C(int a, int b) {
	if (a < b)return 0;
	return q_mul(fact[a], q_mul(invfact[b], invfact[a - b])) % mod;
}
signed main()
{
	init();
	int n, k;
	cin >> n >> k;
	int ans = 0;
	for (int i = 0; i <= min(k, n); i++)
	{
		ans += C(n, i);
		ans %= mod;
	}
	cout << ans;
}

E:对于这道题 复杂度已经被确定为nlogn 或者nsqrt(n)  所以我们尝试枚举c

a+b的值就是n-c 由于a,b为gcd(a,b)的倍数 此时a+b 一定为gcd(a,b)的倍数 此时我们枚举(a+b)的因子就可以找到所有的对 :c,gcd(a,b) 但此时还要考虑每一对有多少个  因为此时 a/d 和 (a+b)/d 互质 我们考虑a/d 的个数就是考虑小于(a+b)/d 且和 其互质的数的个数 :为欧拉函数

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int maxn=1e5+10;//代表前n个数中于n互质的数的个数   方法:ola筛素数
int m[maxn], phi[maxn], p[maxn];//m[i]表示i是不是素数,p为存放素数的数组,phi为欧拉函数
void ola(int x){//1-x中每一位ola函数
    phi[1] = 1;
    for (int i = 2; i <= x; i++){
        if (!m[i]){
            p[++p[0]] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= p[0] && i*p[j] <= x; j++){
        m[p[j] * i] = 1;//利用最小的因数来筛掉该数:p[j]为最小质因子,i为放大倍数
            if (i%p[j] == 0){//看p[j]是否为i的约数,要是i%p[j]==0代表它两不互质
                phi[p[j] * i] = phi[i] * p[j];
                break;
//break的含义为当i=k*p[j]时,要是我们继续循环下去m【i*p【j+1】】=1
//i*p[j+1]=k*p[j]*p[j+1]这个数,会在i=k*p【j+1】时再次被消掉,重复
//同时由于我们是要利用最小的质因子来消掉的所以我们要在当i=k*p[j+1]是消掉他(因为i为放大倍数)
            }
            else{
                phi[p[j] * i] = phi[i] * (p[j] - 1);//p[j]-1就是phi[p[j]],
            }
    }
}
}
signed main()
{
    int n;
    cin>>n;
    ola(n);
    int ans=0;
    for(int c=1;c<=n-2;c++)
    {
        int t=n-c;
        for(int d=1;d*d<=t;d++)//枚举a+b的因数 以为此时假如d为a和b共有的因数那么也是a+b的因数 
        {//此时我们枚举了 c和gcd(a,b) 现在考虑gcd(a,b)的个数: 由于此时a/d和b/d互质 此时我们发现:a/d 和t/d也是互质 此时我们可以发现 a/d <t/d 一定存在所以此时a/d 的个数就是 phi[t/d]
            if(t%d==0)
            {
                ans+=(c*d/__gcd(c,d))*phi[t/d]%mod;
                if(d!=1&&d*d!=t)
                    ans+=(c*t/d/__gcd(c,t/d))*phi[d]%mod;
            }
            ans%=mod;
        }
    }
    cout<<ans%mod;
}



Dashboard - Codeforces Round #819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022 - Codeforces

A:A的话我们可以发现此时翻转可以不限次数,由于我们答案仅由1,n位置决定此时我们考虑3种情况:

1.保留1号位 挑后面最大的安排到n号位

2.保留n号位挑最小的安排到1号位

3.我们此时全部翻转 可以发现此时答案为 相邻两个差的最大值:(前-后)

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
#define int long long
#define endl '\n'
const int maxn = 2e5 + 10;
int a[maxn], n, m;
void solve()
{
	cin >> n;
	int maxx = 0, minn = 1e9;
	int ans = -1e9;
	for (int i = 1; i <= n; i++)
	{		
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++)
	{
		if (i != 1) {
			maxx = max(maxx, a[i]);
		}
		if (i != n)
			minn = min(minn, a[i]);
		if (i != n)
			ans = max(a[i] - a[i + 1], ans);
	}
	if (n == 1)
	{
		cout << 0 << endl;
		return;
	}
	ans = max({ ans,maxx-a[1], a[n] - minn });
	cout << ans << endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while (t--)
		solve();
}

B:对于这道题 我们可以发现我们的最优写法就是维护每个数都有偶数位 除了最大的数可以不用

按这个思路来想 我们假如此时有奇数个位置 可以将前n-1 安排为1 剩下的安排到n位

假如此时有偶数位 我们至少要留出2个位给其他的来分配 其余变为1 因为我们假如将其他位也变大的话 此时是要从剩下的数中掏出来2 所以假如此时剩下的数不为偶数我们就无法分配

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
#define int long long
#define endl '\n'
const int maxn = 2e5 + 10;
int a[maxn], n, m;
void solve()
{
	cin >> n>>m;
	if (m < n)
	{
		cout << "NO" << endl;
    }
	else
	{
		
		if (n % 2 == 1)
		{
			cout << "YES" << endl;
			for (int i = 1; i <= n; i++)
			{
				if (i != n)
				{
					cout << 1 << ' ';
				}
				else
					cout << (m - (n - 1)) << ' ';
			}
			cout << endl;
		}
		else
		{
			int cnt = 0;
			if ((m - (n - 2)) % 2 == 0) {
				cout << "YES" << endl;
				for (int i = 1; i <= n; i++)
				{
					if (i <= n - 2)
					{
						cout << 1 << ' ';
					}
					else
					{
						cout << (m - (n - 2)) / 2 << ' ';
					}
				}
				cout << endl;
			}
			else
			{
				cout << "NO" << endl;
			}
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while (t--)
		solve();
}

C:我们可以发现 对于类似((()))的情况 中间的(())无法和其他的联系 只能作为两独立的东西来看待 但最外围的却可以和其他最外围的相连 所以此时我们只要维护一个每个的深度-1 加起来再+1 就是答案了

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstring>
#include<queue>
#include<string>
#include<stack>
#include<map>
using namespace std;
#define int long long
#define endl '\n'
const int maxn = 2e5 + 10;
string s;
int a[maxn], n, m;
int fa[maxn];
int find(int x)
{
	if (x == fa[x])return x;
	else
		return fa[x] = find(fa[x]);
}
struct node
{
	int id, val;
};
queue<node>st;
void solve()
{
	int len;
	cin >> len;
	cin >> s;
	int cnt = 0;
	int ans = 0;
	for (int i = 2 * len - 1; i >= 0; i--)
	{
		if (s[i] == ')')
		{
			int now = 1;
			while (s[i - now] != '(')
			{
				now++;
			}
			ans += now;
			i = i - now;
			ans -= 1;
			cnt++;
		}
	}
		cout << ans + 1 << endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while (t--)
		solve();
}

D:

考虑此时我们要将哪条变进行变化: 可以发现此时我们将任意一条边变化对蓝色方的减小均为1

假如此时变化的边和蓝色围成环的话此时答案不会减小 

但对于红色方却有讲究假如我们将一个环的一条边划掉的话此时答案不会变大 但假如这条边不少的话此时我们会将区域划分为2分 答案就会+1

所以此时我们要两边均不是环的情况

考虑此时我们利用n-1 将这个图维持一个树 考虑剩下最多3条边是否可能维护围一个环假如会的话我们此时再更新就好了

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstring>
#include<queue>
#include<string>
#include<stack>
#include<map>
using namespace std;
#define int long long
#define endl '\n'
const int maxn = 2e5 + 10;
string s;
int a[maxn], n, m;
int fa[maxn],fa1[maxn];
int find(int x)
{
	if (x == fa[x])return x;
	else
		return fa[x] = find(fa[x]);
}
int find1(int x)
{
	if (x == fa1[x])return x;
	else
		return fa1[x] = find1(fa1[x]);
}
struct node
{
	int l, r;
}e[maxn];
bool vis[maxn];
void solve()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		vis[i] = 0;
	for (int i = 1; i <= n; i++)
		fa[i] = i;
	for (int i = 1; i <= m; i++)
	{
		cin >> e[i].l >> e[i].r;
	}
	for (int i = 1; i <= m; i++)
	{
		int fx = find(e[i].l), fy = find(e[i].r);
		if (fx != fy)
		{
			fa[fx] = fy;
		}
		else
		{
			vis[i] = 1;
		}
	}
	for (int i = 1; i <= n; i++)fa1[i] = i;
	for (int i = 1; i <= m; i++)
	{
		if (vis[i])
		{
			int fx = find1(e[i].l), fy = find1(e[i].r);
			if (fx != fy)
			{
				fa1[fx] = fy;
			}
			else
			{
				
				
				for (int j = 1; j <= n; j++)fa[j] = j;
				fx = find(e[i].l), fy = find(e[i].r);
				fa[fx] = fy;
				for (int j = 1; j <= m; j++)
				{
					if (vis[j] == 0) {
						
						fx = find(e[j].l), fy = find(e[j].r);
						
						if (fx != fy)
						{
							fa[fx] = fy;
						}
						else
						{
							vis[j] = 1;
							break;
						}
					}
				}
				vis[i] = 0;
				break;
			}
		}
	}
	for (int i = 1; i <= m; i++)
		cout << vis[i];
	cout << endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while (t--)
		solve();
}

E及后面的题之后更新 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值