2021牛客寒假算法基础集训营3

内卷
链接:https://ac.nowcoder.com/acm/contest/9983/B
来源:牛客网

题目描述
在一个班级里有\mathit nn个同学,在这个即将进行数据结构期末考试的关头,为了减少内卷,他们决定聚在一起商量对策。
每个人在考试后会得到一个\mathit A,B,C,D,EA,B,C,D,E的等级和一个分数,学校要求得到等级\mathit AA的人不超过\mathit kk个。
已知第\mathit ii个同学在得到五个等级时预期的分数分别为a_{i},b_{i},c_{i},d_{i},e_{i}a
i

,b
i

,c
i

,d
i

,e
i


请问在最理想的情况且不违反上述条件的情况下,他们的预期分数最大值和最小值之差最小为多少。
输入描述:
第一行以空格分隔的两个正整数\mathit n,kn,k。
接下来\mathit nn行每行五个以空格分隔的正整数a_{i},b_{i},c_{i},d_{i},e_{i}a
i

,b
i

,c
i

,d
i

,e
i


1\leq k \leq n \leq 10^{5}1≤k≤n≤10
5

1\leq e_{i} \leq d_{i} \leq c_{i} \leq b_{i} \leq a_{i} \leq 10^{9}1≤e
i

≤d
i

≤c
i

≤b
i

≤a
i

≤10
9

输出描述:
输出一行一个正整数代表答案。
示例1
输入
复制
3 1
100 100 100 100 100
1000 99 99 99 99
101 1 1 1 1
输出
复制
2
说明
第一个人和第二个人取得B等级,第三个人取得A等级的情况下,他们的最大最小分数差为101-99=2。
示例2
输入
复制
3 2
100 1 1 1 1
100 99 99 99 99
100 1 1 1 1
输出
复制
1
说明
第一个人和第三个人取得A等级,第二个人取得B等级的情况下,他们的最大最小分数差为100-99=1。注意由于至多两个人取得A等级,所以没有办法三个人同时考100分。

先把所有的人的分数排序,先按照分数,再把a类的成绩放在后边,因为尽量先不用a类的,然后在双指针往右走,当发现此时已经出现了满足条件的情况,就取最小值,因为要维护很多的东西,需要维护每个人出现的分数有几个,出现的a类分数有几个,用的分数有几个,用的a类分数有几个,在从左向右指的过程中只需要维护这些值就可以了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;
using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e5 + 10;
const int M = N * 10;
const long long mod = 998244353;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

struct Node{
	int val, num;
	bool b;
	bool operator<(const Node &W)const{
		if (val == W.val)   return b < W.b;
		return val < W.val;
	}
}a[N * 5];
int cnt;
int stu[N], cntstu, cnta, sa[N];
int n, k;

signed main(){
	scanf("%lld%lld", &n, &k);
	for (int i = 1; i <= n; i ++){
		int x;
		scanf("%lld", &x);
		a[++ cnt].val = x;
		a[cnt].num = i;
		a[cnt].b = true;
		
		for (int j = 1; j <= 4; j ++){
			int x;
			scanf("%lld", &x);
			a[++ cnt].val = x;
			a[cnt].num = i;
			a[cnt].b = false;
		}
	}
	
	int ans = 0x7f7f7f7f7f7f7f7f;
	sort(a + 1, a + 1 + cnt);
	int j = 1;
	stu[a[1].num] ++;
	if (stu[a[1].num] == 1)    cntstu ++;
	if (a[1].b == 1)    cnta ++;
	if (a[1].b == 1)    sa[a[1].num] ++;
	
	for (int i = 1; i <= cnt; i ++){
		while(j <= cnt){
			if (cnta <= k && cntstu == n){
				ans = min(ans, a[j].val - a[i].val);
				break;
			}
			
			j ++;
			stu[a[j].num] ++;
			if (stu[a[j].num] == 1)    cntstu ++;
			if (a[j].b == 1){
				sa[a[j].num] ++;
				if (stu[a[j].num] == 1)   cnta ++;
			}
		}
		
		stu[a[i].num] --;
		if (stu[a[i].num] == 0)   cntstu --;
		if (stu[a[i].num] == 1 && sa[a[i].num] == 1)   cnta ++;
		if (a[i].b == 1 && stu[a[i].num] == 0)   cnta --;   
    }
	
	cout << ans << endl;
	
	return 0;
}

重力坠击
链接:https://ac.nowcoder.com/acm/contest/9983/C
来源:牛客网

题目描述
在一个二维平面上有\mathit nn个敌人,第\mathit ii个敌人可以描述为一个以(x_{i},y_{i})(x
i

,y
i

)为圆心,r_{i}r
i

为半径的圆。
你每次可以对一个半径为\mathit RR的圆范围内进行攻击(圆心自选,但圆心的横纵坐标必须为整数),对于与你攻击范围有交点的敌人都会被消灭。
你总共可以发动\mathit kk次攻击,问最多能消灭多少敌人。
输入描述:
第一行以空格分隔的三个整数\mathit n,k,Rn,k,R。
接下来\mathit nn行每行以空格分隔的三个整数x_{i},y_{i},r_{i}x
i

,y
i

,r
i


1\leq n \leq 101≤n≤10
1\leq k \leq 31≤k≤3
1\leq r_{i},R \leq 71≤r
i

,R≤7
0\leq |x_{i}|,|y_{i}| \leq 70≤∣x
i

∣,∣y
i

∣≤7
敌人的位置可能会有重叠。
输出描述:
输出一行一个正整数代表答案。
示例1
输入
复制
3 1 1
0 0 1
7 7 1
-2 0 1
输出
复制
2
说明
只能发动一次攻击,可以攻击圆心为(-1,0)的圆,这样可以消灭第一个和第三个敌人。

暴力dfs即可,每次暴力的是当前的这个点放在哪个位置

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);
string str[N];

struct Node{
	int x, y, r;
	bool flag;
}node[100];
bool st[30][30];
int ans;
int n, k, R;
int mindx, mindy, maxdx, maxdy;
vector<PII> v;
map<PII, bool> mp;

bool check(int x1, int y1, int x2, int y2, int r1, int r2){
	if ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) <= (r1 + r2) * (r1 + r2))    return true;
	return false;
}

int calc(){
	int res = 0;
	for (int i = 0; i < v.size(); i ++){
		int xx = v[i].first, yy = v[i].second;
		for (int i = 1; i <= n; i ++){
			if (!node[i].flag)    continue;
			if (check(xx, yy, node[i].x, node[i].y, R, node[i].r)){
				res ++;
				node[i].flag = false;
			}
		}
	}
	return res;
}

void dfs(int u){
	if (u > k){
		//memset(st, 0, sizeof st);
		ans = max(ans, calc());
		for (int i = 1; i <= n; i ++)   node[i].flag = true;
		return;
	}
	
	for (int i = mindx; i <= maxdx; i ++){
		for (int  j = mindy; j <= maxdy; j ++){
			if (mp[{i, j}])   continue;
			mp[{i, j}] = true;
			v.push_back({i, j});
			dfs(u + 1);
			mp[{i, j}] = false;
			v.pop_back();
		}
	}
	
}

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	scanf("%lld%lld%lld", &n, &k, &R);
	for (int i = 1; i <= n; i ++){
		scanf("%lld%lld%lld", &node[i].x, &node[i].y, &node[i].r);
		mindx = min(mindx, node[i].x);
		mindy = min(mindy, node[i].y);
		maxdx = max(maxdx, node[i].x);
		maxdy = max(maxdy, node[i].y);
		node[i].flag = true;
	}
	
	dfs(1);
	
	cout << ans << endl;
	
	return 0;
}

Happy New Year!
链接:https://ac.nowcoder.com/acm/contest/9983/D
来源:牛客网

题目描述
还有一个周就要过年啦!这一天牛牛盯着新的台历出神,他突然想知道对于第\mathit nn年来说,大于\mathit nn且与\mathit nn的数位和相同的最小年份是多少。
一个数字的数位和等于他各数位上的数字之和,例如\text 20212021的数位和等于\text 2+0+2+1=52+0+2+1=5。
输入描述:
一个正整数\mathit nn。
2021\leq n \leq 20302021≤n≤2030
输出描述:
输出一个正整数代表答案。
示例1
输入
复制
2025
输出
复制
2034
说明
2034是比2025大的且数位和等于9的最小正整数

签到

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e9;
const int M = N * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int is_(int x){
	int cnt = 0;
	while(x){
		cnt += x % 10;
		x /= 10;
	}	
	return cnt;
}

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	int n;
	scanf("%lld", &n);
	for (int i = n + 1; ; i ++){
		if (is_(i) == is_(n)){
			cout << i << endl;
			break;
		}
	}
	
	return 0;
}

买礼物
链接:https://ac.nowcoder.com/acm/contest/9983/E
来源:牛客网

题目描述
在卖礼物的超市中有\mathit nn个柜子,每个柜子里都摆放了一个礼物,每个礼物有自己的一个编号,第\mathit ii个柜子里的礼物编号为a_{i}a
i


茶山牛想给牛牛和牛妹买相同编号的礼物,但礼物有可能在某个时刻被其他人买走,而且柜子数量太多,因此茶山牛在某个时刻只想知道某一个柜子区间是否能买到两件相同编号的礼物。
具体来说,有\mathit qq次操作,格式如下:
\text 11 \mathit xx,第\mathit xx个柜子里的礼物被买走,保证此时这个柜子里的礼物还在。
\text 22 \mathit ll \mathit rr,茶山牛询问第\mathit ll到第\mathit rr个柜子未被买走的礼物中是否有两个礼物编号相同。
输入描述:
第一行以空格分隔的两个正整数\mathit n,qn,q。
接下来一行以空格分隔的\mathit nn个正整数a_{i}a
i


接下来\mathit qq行每行一个操作。
1\leq n,q \leq 5×10^{5}1≤n,q≤5×10
5

1\leq a_{i} \leq 10^{6}1≤a
i

≤10
6

1\leq x,l \leq r \leq n1≤x,l≤r≤n
输出描述:
对每次茶山牛的询问输出一行一个整数,如果在指定的区间内有两个礼物编号相同则输出\text 11,否则输出\text 00。
示例1
输入
复制
5 5
1 2 1 2 1
2 2 4
2 2 5
1 2
2 2 4
2 2 5
输出
复制
1
1
0
1
说明
第一次询问的时候可以买到两件编号为2的礼物。第三次询问的时候由于第二件礼物被买走,所以2到4柜子里只有一件编号为1的礼物和一件编号为2的礼物。第四次询问的时候可以买到两件编号为1的礼物。

很明显是线段树,首先要知道维护的是什么,根据的是要查询的是什么,查询的是区间是否有相同的,假如现在搞一个新的区间,区间的每个数指的是他右边第一个和他相等的数的值,那么维护的这个新的区间的最小值,这个最小值如果小于等于r的话,就说明有满足条件的,如何搞出这个新区间,需要拿更多的数来维护,搞一个last数组,这个值出现过的话,那么前一个数就能维护出来这个值。然后还有一个修改操作,如何修改,把当前这个值删了,会影响哪些数,会影响前一个数,前一个数的新数组会改变,会影响这个数的新数组的值,会影响下一个数,如何维护,再拿一个pre数组和一个ne数组来维护,在修改的时候,同时修改需要维护的所有的数即可

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;

typedef long long LL;

struct Segment_tree
{
	int l, r;
	int mind;
} tr[N * 4];

int n, m;
int a[N], b[N], pre[N], ne[N], last[N];

void pushup(Segment_tree &u, Segment_tree &l, Segment_tree &r)
{
	u.mind = min(l.mind, r.mind);
}

void pushup(int u)
{
	pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r)
{
	if (l != r) tr[u] = {l, r};
	else
	{
		tr[u] = {l, r, a[l]};
		return;
	}
	
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	
	pushup(u);
}

void modify(int u, int pos, int val)
{
    if (tr[u].l == tr[u].r)
    {
        tr[u].mind = val;
        return;
    }
     
    int mid = tr[u].l + tr[u].r >> 1;
    if (pos <= mid) modify(u << 1, pos, val);
    else modify(u << 1 | 1, pos, val);
     
    pushup(u);
}

Segment_tree query(int u, int l, int r)
{
	if (tr[u].l >= l && tr[u].r <= r) return tr[u];

	int mid = tr[u].l + tr[u].r >> 1;
	if (r <= mid) return query(u << 1, l, r);
	if (l > mid) return query(u << 1 | 1, l, r);
	
	Segment_tree total, l_tree, r_tree;
	l_tree = query(u << 1, l, r);
	r_tree = query(u << 1 | 1, l, r);
	
	pushup(total, l_tree, r_tree);
	
	return total;
}

int main()
{
	scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= n; i ++){
		scanf("%d", &b[i]);
		if (last[b[i]]){
			ne[last[b[i]]] = i;
			pre[i] = last[b[i]];
		}
		else{
			pre[i] = -1;
		}
		ne[i] = n + 1;
		
		last[b[i]] = i;
	}
	
	for (int i = 1; i <= n; i ++){
		a[i] = ne[i];
	}
	
	build(1, 1, n);
	
	while(m --){
		int op, x;
		scanf("%d%d", &op, &x);
		//cout << op << " " << x << "---" << endl;
		if (op == 1ll){
			if (pre[x]){
				ne[pre[x]] = ne[x];
				modify(1, pre[x], ne[x]);
			}
			if (ne[x] != n + 1){
				pre[ne[x]] = pre[x];
			}
			
			pre[x] = -1, ne[x] = n + 1;
			modify(1, x, n + 1);
		//	cout << "---" << endl;
		}
		else{
			int r;
			scanf("%d", &r);
			if (r >= query(1, x, r).mind)   cout << "1" << endl;
			else   cout << "0" << endl;
		}
	}
	
}


匹配串
链接:https://ac.nowcoder.com/acm/contest/9983/F
来源:牛客网

题目描述
一个模式串指仅包含小写英文字母和至少一个’#‘的字符串,其中’#‘可以匹配一段任意长度的任意小写字母字符串。
一个匹配串指待匹配的只包含小写字母的字符串。
一个模式串和一个匹配串相匹配当且仅当把模式串里面的’#‘全部分别替换成空或一段小写字母字符串后,两个串完全相同。
现在给出\mathit nn个模式串,问有多少不同的匹配串与这些模式串全部相匹配。
如果答案有无穷多个,输出\text -1-1。
输入描述:
第一行一个正整数\mathit nn。
接下来\mathit nn行每行一个只包含小写字母和’#'的模式串。
1\leq n \leq 10^{6}1≤n≤10
6

保证输入模式串的长度总和不超过10^{6}10
6
且每个模式串至少包含一个’#’
输出描述:
一行一个整数代表答案。
如果答案有无穷多个,输出\text -1-1。
示例1
输入
复制
2
a#
b#
输出
复制
0
示例2
输入
复制
2
a#x#c
a#c
输出
复制
-1

链接:https://ac.nowcoder.com/acm/contest/9983/F
来源:牛客网

题目描述
一个模式串指仅包含小写英文字母和至少一个’#‘的字符串,其中’#‘可以匹配一段任意长度的任意小写字母字符串。
一个匹配串指待匹配的只包含小写字母的字符串。
一个模式串和一个匹配串相匹配当且仅当把模式串里面的’#‘全部分别替换成空或一段小写字母字符串后,两个串完全相同。
现在给出\mathit nn个模式串,问有多少不同的匹配串与这些模式串全部相匹配。
如果答案有无穷多个,输出\text -1-1。
输入描述:
第一行一个正整数\mathit nn。
接下来\mathit nn行每行一个只包含小写字母和’#'的模式串。
1\leq n \leq 10^{6}1≤n≤10
6

保证输入模式串的长度总和不超过10^{6}10
6
且每个模式串至少包含一个’#’
输出描述:
一行一个整数代表答案。
如果答案有无穷多个,输出\text -1-1。
示例1
输入
复制
2
a#
b#
输出
复制
0
示例2
输入
复制
2
a#x#c
a#c
输出
复制

很明显,结果只有两种可能,要么是无数种,要么只有一种,只有当第一个字母和最后一个字母都相等的时候就是无数种,#和任何的字母都相等,其余的就是没有

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);
string str[N];

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	int n;
	scanf("%lld", &n);
	

	char c1, c2;
	for (int i = 1; i <= n; i ++){
		cin >> str[i];
		if (str[i][0] != '#')   c1 = str[i][0];
		if (str[i][str[i].size() - 1] != '#')   c2 = str[i][str[i].size() - 1]; 
	}
	
	bool flag = true;
	for (int i = 1; i <= n; i ++){
		int cnt = 0;
		if (str[i][0] == c1 || str[i][0] == '#')   cnt ++;
		if (str[i][str[i].size() - 1] == c2 || str[i][str[i].size() - 1] == '#')   cnt ++;
		if (cnt <  2)   flag = false;   
	}
	
	if (flag)   cout << "-1" << endl;
	else  cout << "0" << endl;
	
	return 0;
}

糖果
链接:https://ac.nowcoder.com/acm/contest/9983/G
来源:牛客网

题目描述
在一个幼儿园里面有\mathit nn个小朋友,分别编号\text 1,2,…,n1,2,…,n。在这些小朋友中有一些小朋友互为朋友关系,总共有\mathit mm对朋友。
作为幼儿园老师,你想买一些糖果分给小朋友,你知道第\mathit ii个小朋友想要至少a_{i}a
i

个糖果,否则他就会不开心。
同时,如果一个小朋友得到的糖果数小于他某个朋友得到的糖果数,他也会不开心。
请问你最少买多少糖果才能保证每个小朋友都不会不开心呢?
输入描述:
第一行以空格分隔的两个整数\mathit n,mn,m。
第二行以空格分隔的\mathit nn个正整数a_{i}a
i


接下来\mathit mm行每行以空格分隔的两个正整数\mathit u,vu,v,代表\mathit uu是\mathit vv的朋友,\mathit vv是\mathit uu的朋友。
1\leq n\leq 10^{6}1≤n≤10
6

0\leq m\leq 10^{6}0≤m≤10
6

1\leq a_{i} \leq 10^{9}1≤a
i

≤10
9

1\leq u,v \leq n,u≠v1≤u,v≤n,u


=v
输出描述:
购买的最少糖果数以保证每个小朋友都不会不开心。
示例1
输入
复制
3 1
1 2 3
1 2
输出
复制
7
说明
给第三个小朋友买3个糖果,前两个小朋友都买2两个糖果,总共至少买7个糖果。注意如果给第一个小朋友只买了1个糖果,那么他在看到自己的好朋友2有2个糖果的情况下,他就会不开心。

爆搜或者并查集都可以

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

bool st[N];
int h[N], e[M], ne[M], idx;
int n, m;
int a[N];

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

int cnt;
int dfs(int u){
	st[u] = true;
	cnt ++;
	int res = a[u];
	for (int i = h[u]; ~i; i = ne[i]){
		int j = e[i];
		if (st[j])   continue;
		res = max(res, dfs(j));
	}
	return res;
}

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	memset(h, -1, sizeof h);
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i ++)   scanf("%lld", &a[i]);
	
	while(m --){
		int a, b;
		scanf("%lld%lld", &a, &b);
		add(a, b), add(b, a);
	}
	
	int ans = 0;
	for (int i = 1; i <= n; i ++){
		if (!st[i]){
			cnt = 0;
			ans += dfs(i) * cnt;
		}
	}
	
	cout << ans << endl;
	
	return 0;
}

#include<iostream>

using namespace std;
typedef long long LL;
const int N=1e6+10;

int a[N],b[N],p[N],se[N];
int n,m;
LL ans;

int find(int x)
{
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        p[i]=i,se[i]=1;
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int px=find(x),py=find(y);
        if(px!=py)
        {
            se[px]+=se[py];
            b[px]=max(b[px],b[py]);
            p[py]=p[x];
        }
    }
    for(int i=1;i<=n;i++) if(find(i)==i) ans+=se[i]*b[i];
    cout<< ans <<endl;
    return 0;
}

数字串
链接:https://ac.nowcoder.com/acm/contest/9983/H
来源:牛客网

题目描述
牛牛发现了一种方法可以将只包含小写字母的字符串按照以下方式使其转换成一个数字串:
取其中的每个字母,\mathit aa转换为\text 11,\mathit bb转换为\text 22…\mathit zz转换为\text 2626,然后将这些数字拼接起来。
例如,\mathit abczabcz可以转换为\text 1232612326。
现在给出一个只包含小写字母的字符串\mathit SS,你需要找到一个只包含小写字母的字符串\mathit TT,使得两个串不相同但是能转换成相同的数字串。
输入描述:
一行一个长度不超过10^{6}10
6
的小写字母字符串\mathit SS。
输出描述:
一行一个长度不超过2×10^{6}2×10
6
的小写字母字符串\mathit TT。
如果无解,请输出\text -1-1。
如果答案有解且你输出的字符串包含了除了小写字母以外的字符或长度超过了2×10^{6}2×10
6
,那么你会得到“答案错误”的返回结果。
否则如果答案有解且你的答案与输入的字符串可以转换为一样的数字串,那么你的答案会被认为是正确的。
示例1
输入
复制
cwc
输出
复制
cbcc
说明
cwc和cbcc转换成的数字串都是3233
示例2
输入
复制
ccc
输出
复制
-1

模拟题,特判20和10的情况

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int cnt[N];

struct node{
	char c1;
	char c2;
};

map<int, char> mp2;
map<char, int> mp1;

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	mp1['a'] = 1;
	mp1['b'] = 2;
	mp1['c'] = 3;
	mp1['d'] = 4;
	mp1['e'] = 5;
	mp1['f'] = 6;
	mp1['g'] = 7;
	mp1['h'] = 8;
	mp1['i'] = 9;
	mp1['j'] = 10;
	mp1['k'] = 11;
	mp1['l'] = 12;
	mp1['m'] = 13;
	mp1['n'] = 14;
	mp1['o'] = 15;
	mp1['p'] = 16;
	mp1['q'] = 17;
	mp1['r'] = 18;
	mp1['s'] = 19;
	mp1['t'] = 20;
	mp1['u'] = 21;
	mp1['v'] = 22;
	mp1['w'] = 23;
	mp1['x'] = 24;
	mp1['y'] = 25;
	mp1['z'] = 26;
	
	mp2[1] = 'a';
	mp2[2] = 'b';
	mp2[3] = 'c';
	mp2[4] = 'd';
	mp2[5] = 'e';
	mp2[6] = 'f';
	mp2[7] = 'g';
	mp2[8] = 'h';
	mp2[9] = 'i';
	mp2[10] = 'j';
	mp2[11] = 'k';
	mp2[12] = 'l';
	mp2[13] = 'm';
	mp2[14] = 'n';
	mp2[15] = 'o';
	mp2[16] = 'p';
	mp2[17] = 'q';
	mp2[18] = 'r';
	mp2[19] = 's';
	mp2[20] = 't';
	mp2[21] = 'u';
	mp2[22] = 'v';
	mp2[23] = 'w';
	mp2[24] = 'x';
	mp2[25] = 'y';
	mp2[26] = 'z';
	
	string str;
	cin >> str;
	string str1 = "";
	for (int i = 0; i < str.size(); i ++){
		if (mp1[str[i]] >= 1 && mp1[str[i]] <= 9){
			if (mp1[str[i + 1]] >= 1 && mp1[str[i + 1]] <= 9 && mp1[str[i]] * 10 + mp1[str[i + 1]] <= 26){
				int temp = mp1[str[i]] * 10 + mp1[str[i + 1]];
				str1 += mp2[temp];
				i ++;
			}
			else{
				str1 += str[i];
			}
		}
		else{
			int temp1 = mp1[str[i]] / 10;
			int temp2 = mp1[str[i]] % 10;
			if (temp2 == 0){
				str1 += str[i];
				continue;
			} 
			str1 += mp2[temp1];
			str1 += mp2[temp2];
		}
	}
	
	if (str1 == str){
		cout << "-1" << endl;
	}
	else   cout << str1;
	
	return 0;
}

序列的美观度
链接:https://ac.nowcoder.com/acm/contest/9983/I
来源:牛客网

题目描述
设一个长度为\mathit mm的序列\mathit SS的美观度等于有多少个整数\mathit ii满足1\leq i \leq m-11≤i≤m−1且S_{i}=S_{i+1}S
i

=S
i+1

,其中S_{i}S
i

代表序列\mathit SS的第\mathit ii个元素。
给出一个长度为\mathit nn的序列\mathit aa,问在他的所有子序列美观度最大是多少。
某个序列的子序列是从最初序列通过去除某些元素(也可以不去除,即序列本身也是子序列)但不破坏余下元素的相对位置(在前或在后)而形成的新序列。
输入描述:
第一行一个正整数\mathit nn。
接下来一行\mathit nn个以空格分隔的正整数a_{i}a
i


2\leq n \leq 10^{6}2≤n≤10
6

1\leq a_{i} \leq 10^{6}1≤a
i

≤10
6

输出描述:
输出一个整数代表答案。
示例1
输入
复制
5
1 1 2 3 2
输出
复制
2
说明
美观度最大的子序列为[1,1,2,2]
示例2
输入
复制
7
1 1 2 2 2 1 1
输出
复制
4

正解是dp,我这里考虑的是每次依次找到最接近的相同的数即可,然后就不考虑那些之前的数就可以,dp也非常简单,维护一个前一个相同的数加1就可以了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int cnt[N];

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	int n;
	scanf("%lld", &n);
	
	int ans = 0;
	vector<int> v;
	for (int i = 1; i <= n; i ++){
		int x;
		scanf("%lld", &x);
		if (cnt[x]){
			ans ++;
			cnt[x] = 0;
			for (int j = 0; j < v.size(); j ++)
			cnt[v[j]] = 0;
			v.clear();
		}
		cnt[x] ++;
		v.push_back(x);
	}
	
	cout << ans << endl;
	
	return 0;
}

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <bits/stdc++.h> 

//using namespace __gnu_cxx;
using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

int yy[1010];

void init(){
	for (int i = 1; i <= 96; i ++)   yy[i] = i + 1;
}

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e6 + 10;
const int M = 2 * N;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int f[N], pos[N];

signed main(){
//	freopen("stdin.txt", "r", stdin);
//	freopen("stdout.txt", "w", stdout);
//	ios;
	int n;
	scanf("%lld", &n);
	
	int ans = 0;
	
	for (int i = 1; i <= n; i ++){
		int x;
        scanf("%lld", &x);
        if (pos[x])    f[i] = max(f[i - 1], f[pos[x]] + 1);
        else   f[i] = f[i - 1];
        
        ans = max(ans, f[i]);
        pos[x] = i;
	}
	
	cout << ans << endl;
	
	return 0;
}

加法和乘法

链接:https://ac.nowcoder.com/acm/contest/9983/J
来源:牛客网

题目描述
有一天牛牛和牛妹在做游戏,规则如下:
桌面上摆着\mathit nn张纸牌,每张纸牌上写着一个正整数,由牛牛先手轮流执行以下操作:
\text 1.1.如果桌面上只剩一张纸牌,游戏结束,这张纸牌上的数字如果是奇数则牛牛胜利,反之牛妹胜利。
\text 2.2.当前行动玩家选择两张纸牌,设上面的数字分别为\mathit X,YX,Y,接下来玩家从加法和乘法中选择一个并应用到这两个数字上,得到结果为\mathit ZZ,接下来将选择的两张纸牌丢弃,并拿一张新的纸牌放到桌面上,在上面写上\mathit ZZ。
假设双方均以最优策略行动,最后谁会赢?
输入描述:
第一行一个正整数\mathit nn,代表开始的纸牌数。
第二行\mathit nn个空格分隔的正整数a_{i}a
i

代表开始纸牌上的数字。
1\leq n \leq 10^{6}1≤n≤10
6

1\leq a_{i} \leq 10^{9}1≤a
i

≤10
9

输出描述:
如果牛牛能赢,输出\mathit NiuNiuNiuNiu,否则输出\mathit NiuMeiNiuMei。
示例1
输入
复制
3
233 2333 23333
输出
复制
NiuMei
示例2
输入
复制
4
1 1 1 1
输出
复制
NiuNiu

博弈的问题,首先考虑最终态,然后倒着往回推,什么可以转化成奇数,什么又可以转换成偶数,我们发现不管什么情况都可以转换成偶数,但是当都是偶数的时候不能转化成奇数,所以当牛妹最后一步的时候牛妹是必胜的,但是牛牛最后一步的时候牛牛不一定是必胜的,牛妹怎样就可以给牛牛留下两个偶数,牛牛肯定删一个偶数,牛妹可以删除两个奇数变成一个偶数,所以只要一开始有两个偶数的话,牛妹级赢了,然后因为数据比较小,还可以模拟

#include<iostream>

using namespace std;

int main()
{
    int n;
    cin>>n;
    int res=0;
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        if(x&1) res++;
    }
    if(n&1)
    {
        if(n==1 && x&1) puts("NiuNiu");
        else puts("NiuMei");
    }
    else
    {
        if(res==n || res==n-1) puts("NiuNiu");
        else puts("NiuMei");
    }
    return 0;
}
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
//#include <bits/stdc++.h> 

using namespace std;
using namespace __gnu_cxx;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
//#define x first
//#define y second

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

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e5 + 10;
const int M = N * 10;
const int mod = 1e9 + 7;
const int PP = 131;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

signed main(){
	int n;
	scanf("%lld", &n);
	
	int cnt1 = 0, cnt2 = 0;
	for (int i = 1; i <= n; i ++){
		int x;
		scanf("%lld", &x);
		if (x & 1)   cnt1 ++;
		else cnt2 ++;
	}
	
	bool flag = false;
	
	while(n > 1){
		if (!flag){
			if (cnt1){
				if (cnt2)    cnt2 --;
				else   cnt1 --;
			}
			else  cnt2 --;
		}
		else{
			if (cnt1){
				if (cnt1 >= 2){
					cnt1 -= 2;
					cnt2 ++;
				}
				else cnt1 --;
			}
			else  cnt2 --;
		}
		
		if (!flag)   flag = true;
		else  flag = false;
		n --;
	//	cout << flag << " " << cnt1 << " " << cnt2 << endl;
	}
	
	if (cnt1){
		cout << "NiuNiu" << endl;
	}
	else cout << "NiuMei" << endl;
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值