Codeforces Round #788 (Div. 2)解题报告

A. Prof. Slim

题意:给定一个长度为n的整数数列,可以选定一个正数和一个负数交换他们的符号,问是否能将其构造成非递减序列
把所有的负号放前面,检查一下是否非递减即可
ac代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n'
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 500010,INF = 0x3f3f3f3f,mod = 998244353 ;
const double INFF = 0x7f7f7f7f7f7f7f7f;

int n,m,x;
int a[N];


int main()
{
	ios;
	int t;
	cin >> t;
	while(t --)
	{
		bool f = true;
		int sum = 0;
		cin >> n;
		for(int i = 1;i <= n;i ++) 
		{
			cin >> a[i];
			if(a[i] < 0) sum ++;
		}
		for(int i = 1; i <= n;i ++)
		{
			if(i <= sum) a[i] = - abs(a[i]);
			else a[i] = abs(a[i]);
		}

		for(int i = 2;i <= n;i ++)
		{
			if(a[i] < a[i - 1]) 
			{
				f = false;
				break;
			}
		}
		if(f) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

B. Dorms War

题意:给定一个长度为n的字符串,和k个特殊字符,定义操作:将字符串内所有特殊字符前的一个字符删除,问最多可做多少次这样的操作。
特殊字符将整个字符串分为几段区间,取区间长度最大的即可
ac代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n'
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 500010,INF = 0x3f3f3f3f,mod = 998244353 ;
const double INFF = 0x7f7f7f7f7f7f7f7f;

int n,m,x;
int a[N];


int main()
{
	ios;
	int t;
	cin >> t;
	while(t --)
	{
		string s;
		cin >> n >> s;
		map<char,int> mp;
		cin >> x;
		for(int i = 0;i < x;i ++) 
		{
			char c;
			cin >> c;
			mp[c] ++;
		}

		int maxv = 0,t = 0;
		for(int i = 0;i < n;i ++)
		{
			if(mp[s[i]] == 0) t ++;
			else 
			{
				maxv = max(maxv,t);
				t = 1;
			}
		}

		cout << maxv << endl;

	}
	return 0;
}

C. Where is the Pizza?

题意:给定两个长度为n的排列a,b,c[i] 为 a[i] or b[i],有些c[i] 已经给定,求使得c也为一个排列的方案数。
对位置分组,使得每组中的数字个数都是二,对一个组内讨论,任取一个位置,如果这个选择确定了的话,那么相应的组内有这个数字的另外一个位置选择也被确定,....,最终会发现每组只有两种方案,如果对于一个组内有一个位置已经被选,那么就只有一种方案,最后分类计数原理,每组方案数相乘即可。
也可以 看作是建图找环,每个环就是上面说的组,用并查集维护即可。
ac代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n'
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 500010,INF = 0x3f3f3f3f,mod = 1e9 + 7 ;
const double INFF = 0x7f7f7f7f7f7f7f7f;

int n,m,x;
int a[N],b[N],c[N];
int p[N];
bool st[N];
int find(int x)
{
	if(x != p[x]) return p[x] = find(p[x]);
	return x;
}

LL qmi(int a,int k,int p)
{
	LL res = 1;
	while(k)
	{
		if(k & 1) res = 1LL * res * a % p;
		k >>= 1;
		a = 1LL * a * a % p;
	}
	return res;
}

int main()
{
	ios;
	int t;
	cin >> t;
	while(t --)
	{
		cin >> n;
		vector<PII> v;
		for(int i = 1; i <= n;i ++) p[i] = i;
		memset(st,0,sizeof (bool) * (n + 4));
		for(int i = 0;i < n;i ++) cin >> a[i];

		for(int i = 0;i < n;i ++) cin >> b[i];

		for(int i = 0;i < n;i ++) cin >> c[i];

		int cnt = 0;
		for(int i = 0;i < n;i ++)
		{
			int x = find(a[i]),y = find(b[i]);
			if(x != y)
			{
				p[x] = y;
			}
			else cnt ++;

		}

		for(int i = 0;i < n;i ++)
		{
			if(c[i])
			{
				int x = find(c[i]);
				if(!st[x])
				{
					cnt --;
					st[x] = true;
				}
			}
			else if(a[i] == b[i])
			{
				int x = find(a[i]);
				if(!st[x])
				{
					cnt --;
					st[x] = true;
				}
			}
		}

		cout << qmi(2,cnt,mod) << endl;		
	}
	return 0;
}

D. Very Suspicious

题意:给定一个蜂窝图,问最少切几刀可以获得n个等边三角形。刀只能有三种角度(相较x轴):\(0^。,60^。,120^。\)
画图模拟,可以发现每切一刀增加的三角形数量为与其相交的直线的数量 * 2,贪心的切,找到规律
为 0 2 4 | 4 6 8 | 8 10 12,打表做前缀和再二分即可,a[i] = (a[i - 3] / 2 - 2) * 2.


ac代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n'
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 1000010,M = 500010,INF = 0x3f3f3f3f,mod = 1e9 + 7 ;
const double INFF = 0x7f7f7f7f7f7f7f7f;

int n,m,x;
LL a[N],b[N],c[N];
bool st[N];

int main()
{
	ios;
	int idx = 1;
	a[2] = 2,a[3] = 4;
	for(int i = 4;i <= 40000;i ++)
	{
		a[i] = (a[i - 3] / 2 + 2) * 2;
	}
	for(int i = 1;i <= 40000;i ++) a[i] += a[i - 1];
	int t;
	cin >> t;
	while(t --)
	{
		cin >> n;
		int l = 1,r = 40000 - 1;
		while(l < r)
		{
			int mid = l + r >> 1;
			if(a[mid] >= n) r = mid;
			else l = mid + 1;
		}
		cout << l << endl;
	}
	return 0;
}
posted @ 2022-05-07 17:28  notyour_young  阅读(57)  评论(2编辑  收藏  举报