Codeforces Round #811 (Div. 3)

这次的div3整体不难就是有些细节问题,有两道题因为细节问题gg了.


一、A - Everyone Loves to Sleep

  • 题目:
    给你小明的睡觉时间,给你小明订的闹钟个数和每个闹钟的时间,闹钟响,小明就会起来,问你小明从睡觉到醒来用了多长时间
  • 思路
    直接"乱炖",把所有的时间都变成分钟,然后24小时是一个周期,就是当前的(闹钟时间 - 睡觉时间 + 24 * 60) % (60 * 24)
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 1e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
int a[N];

void solve()
{
	int n,h,m; cin >> n >> h >> m;
	int k = h * 60 + m;
	int t = INF;
	for(int i = 1;i <= n;i ++ )
	{
		int a,b; cin >> a >> b;
		int q = a * 60 + b;
		
		int s = (q - k + 24 * 60) % (24 * 60);
		t = min(t,s);
		
	}
	
	cout << t / 60 << ' ' << t % 60 << endl;
}
signed main() 
{
	ios;int T;cin >> T;
	while(T -- ) solve();

    return 0;
}

二、B - Remove Prefix

  • 题目:
    你每次可以删除开头的一个数字,问你几次可以把数组A变成没有重复数字的数组
  • 思路:
    因为是从开头删除的,所以直接从后面往前面算,如果 x 出现两次的话,那就直接记录此时的下标,输出就行
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 1e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
int a[N];
int b[N];
void solve()
{
	int n; cin >> n;
	memset(b,0,sizeof b);
	for(int i = 1;i <= n;i ++ ) cin >> a[i];
	int id = 0;
	for(int i = n;i >= 1;i -- )
	{
		b[a[i]]++;
		if(b[a[i]] >= 2)
		{
			id = i;
			break;
		}
	}
	
	cout << id << endl;
}
signed main() 
{
	ios;int T;cin >> T;
	while(T -- ) solve();

    return 0;
}

三、C - Minimum Varied Number

  • 题目:
    给你一个数字n,然后你需要找到一个最小的数字x,使得x的每一位相加之和是n,输出x
  • 思路:
    因为想要x最小,所以贪心从9一直到1,也就是从低位9到高位1过渡
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 1e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
int a[N];
int b[N];
void solve()
{
	int n; cin >> n;
	string s;
	vector<int>res;
	int k = 9;
	while(n != 0)
	{
		if(n >= k)
		{
			n -= k;
			res.pb(k);
			
		}
		k--;
		
	}
	
	for(int i = res.size() - 1;i >= 0;i --) cout <<  res[i];
	cout << endl;
}
signed main() 
{
	ios;int T;cin >> T;
	while(T -- ) solve();

    return 0;
}

四、D - Color with Occurrences

  • 题目:
    给你一个标准字符串T,给你n个匹配字符串S,如果S[i]是T的子串,就可以把T中与S[i]相同的字串染色,问你T被全部染色的最小次数是多少,每次选择的是哪一个S

  • 思路:
    这个也是贪心,枚举每一个T[i],每次更新最大匹配长度,那如何计算次数,rmax为最大匹配长度,r为rmax更新之前的值,如果当前的i > r 代表此时依然没有染色完全,此时次数ans++, 如果当前 i == rmax,并且更新完成以后i == rmax,代表肯定失败,注意细节.代码写的有点不好,凑活看吧
    在这里插入图片描述

  • 代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 20,M = 1e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
vector<PII> res;
bool st[N];
void solve()
{
	string t; cin >> t;
	int n; cin >> n;
	string s[N];
	for(int i = 1;i <= n;i ++ ) cin >> s[i]; // 重复的越少越好并且越大越好
	int ans = 0;
	int r = 0,rmax = -1;
	int g = 0;
	
	res.clear();
	int len = 0,x = 0;
	
	for(int i = 0;i < t.size();i ++ ) // 看每一个字符最远能到多少 
	{
		if(i > r)
		{
			ans++;
			res.pb({len,x + 1});
			r = rmax;
			if(len == 0)break;
		}
		int p = 0;
		for(int j = 1;j <= n;j ++ )
		{
			int f = 0;
			int w = i;
			for(int k = 0;k < s[j].size();k ++,w ++)
			{
				if(t[w] != s[j][k])
				{
					f = 1;break;
				}		
			}

			if(f == 0) // 匹配了 那我要最大的 
			{
				if(w > rmax)
				{
					rmax = w;
					x = i;
					len = j;
				}
				
				if(w == t.size())
				{
					p = 1;
					break;
				}
			}
			
		}
		
		if(p == 1)
		{
			g =1;
			ans++; 
			res.pb({len,x + 1});
			if(len == 0)g = 0;
			break;
		}

		if(i == rmax)break; // 错误的 
		
	}
	
	if(g)
	{
		    cout << ans << endl;
		 	for(int i = 0;i < res.size();i ++ )
		 	cout << res[i].fi << ' ' << res[i].se << endl;
		 
	}
	else cout << "-1" << endl;
		
}
signed main() 
{
	ios;int T;cin >> T;
	while(T -- ) solve();

    return 0;
}

五、E - Add Modulo 10

  • 题目
  • 给你一个数组A,每一次操作都可以使得A[i] = A[i] + (A[i] % 10),问你能否使得A中每一个元素都相等
  • 思路:
    因为个位数只有0到9,当A[i]的个位数为0时,所有的A[i]经过操作后都得是这个数字,这个有个规律,就是如果A[i] % 10 == 0 ,那A[i]不变,A[i] % 10 == 5,那A[i]最多变一次为A[i] + 5,其他数字经过几次变换最终个位数都是按照 2 4 8 6 的周期进行,也就是每一次都必须加 20 (2 + 4 + 8 + 6)所以我们可以把A[i] 都变成个位数字为2的A[i],然后所有的A[i]都必须符合 A[i] + k1 * 20 == A[j] + k2 * 20,化简就是每一个都要符合 (A[i] - A[j]) % 20 == 0,这里我们就让q = 最大的A[i],所以最后每一个A[i]都必须符合(q - A[i]) % 20 == 0
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 1e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
int a[N];
void solve()
{
	int n; cin >> n;int d = 0;
	int q = -1;
	for(int i = 1;i <= n;i ++ ) cin >> a[i];
	for(int i = 1;i <= n;i ++ )
	{
		if(a[i] % 10 == 5) a[i] += 5,d++;
		else if(a[i] % 10 == 0) d++;
		else
		{
			while(a[i] % 10 != 2)
			{
				a[i] = a[i] + (a[i] % 10);
			}
			
			q = max(q,a[i]);
		}
	}
	int f = 0;
	if(d == n)
	{	
		for(int i = 2;i <= n;i ++ )
		if(a[i] != a[1])
		{
			f = 1;break;
		}
		
	}
	else if(d > 0) f = 1;
	else
	{
		for(int i = 1;i <= n;i ++ )
		{
			if((q - a[i]) % 20 != 0)
			{
				f = 1; break;
			}
		}
	}
	
	cout << (f == 0? "Yes" : "No") << endl; 
}

signed main() 
{
	ios;int T; cin >> T;  
	while(T -- ) solve();

    return 0;
}

六、F - Build a Tree and That Is It

  • 题目:
    无根树,n个点,给你D(1,2),D(2,3),D(3,1)的距离,问你是否能构造出这个树
  • 思路:
    这个思路很好想,就是代码写的细节很多,我们先以 1为根节点,先固定2的点(固定3的点也一样) 第一种情况在代码中写出来了,这里分析第二种情况,代码写的风格不是很节俭
    在这里插入图片描述
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 4e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
vector<PII> res;

void solve()
{
	int n,d12,d23,d31; cin >> n >> d12 >> d23 >> d31;
	res.clear(); 
    if(d12 == d23 + d31) // 一条链子上面并且 2在最下面 3在中间 
	{
		cout << "YES" << endl;
		int k = 1,s = 4,d = 1;
		while(d <= d12)
		{
			if(d == d31)
			{
				res.pb({k,3});
				k = 3;
				d++;
				continue;
			}
			
			if(d == d12)
			{
				res.pb({k,2});
				break;
			}
			else
			{
				res.pb({k,s});
				k = s;
				s++;
			}
			
		
			d++;	
		}
		
		for(int i = s;i <= n;i ++ )
		{
			cout << 1 << ' ' << i << endl;
		}
		
		for(auto x:res)
		cout << x.fi << ' ' << x.se << endl;
	
	}
	else
	{
		if((d12 + d31 - d23) % 2 != 0) cout << "NO" << endl;
		else
		{
			int p = (d12 + d31 - d23) / 2; // 在p这个点分开 
			if(p + d23 + 1 > n || p < 0 || p > d12 || p > d31) cout << "NO" << endl;
			else
			{
				cout << "YES" << endl;
				int k = 1,s = 4,d = 1,u;
				
				while(d <= d12)
				{
					if(d == p)
					{
						u = s;
					}
					
					if(d == d12)
					{
						res.pb({k,2});
					}
					else
					{
					res.pb({k,s});	
					k = s;
					s++;
					}
						
					d++;		
				}
				

				if(p == 0)
				k = 1,d = 1;
				else if(p == d12)
				k = 2,d = p + 1;
				else
				k = u,d = p + 1;
				
				
				while(d <= d31)
				{
					if(d == d31)
					{
						res.pb({k,3});
					}
					else
					{
						res.pb({k,s});
						k = s;
						s++;	
					}	
					d++;		
				}
				
		for(int i = s;i <= n;i ++ ) cout << 1 << ' ' << i << endl;
		for(auto x:res)
		cout << x.fi << ' ' << x.se << endl;
				
				
			}
			
		}
	} 
}

signed main() 
{
	ios;int T; cin >> T;  
	while(T -- ) solve();

    return 0;
}

七、G - Path Prefixes

  • 题目:
    给你n个点,1为根节点 然后给你边,每条边都有两个权值A[i],B[i],从1开始到点 u 路径中的所有边的A[i]之和 >= 从1开始到点 v 路径中的所有边的B[i]之和(v是1到u路径中的某个点,同时这个v点的深度尽可能的大) 求出每一个点u对应v的最大深度
  • 思路:
    树上前缀和 dfs , bfs 都行,然后寻找点v的话,就是利用倍增思想,快速找到符合条件的v点,或者用二分求也行,我用的是bfs
  • 代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define all(x) x.begin(),x.end()
#define pb push_back
#define int long long 
#define PII pair<int,int>
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

using namespace std;
const int N = 2e5 + 100,M = 4e5 + 100,mod = 1e9 + 7,INF = 0x3f3f3f3f;
int h[N],e[N],a[N],b[N],ne[N],idx;
int sa[N],sb[N];
int res[N];
int fa[N][20];
int d[N];
void add(int u,int v,int w1,int w2)
{
	e[idx] = v,a[idx] = w1,b[idx] = w2,ne[idx] = h[u],h[u] = idx ++ ;
}

int check(int x,int val) // 2 16
{
	for(int i = 19;i >= 0;i -- )
	{
		if(sb[fa[x][i]] >= val)
		x = fa[x][i];
	}
	
	if(sb[x] <= val) return d[x];
	else
	return d[fa[x][0]];
}

void bfs()
{
	queue<int> q; q.push(1); d[1] = 0;
	
	while(q.size())
	{
		int t = q.front();q.pop();
		
		res[t] = check(t,sa[t]);
		
		for(int i = h[t];i != -1;i = ne[i])
		{
			int j = e[i];
			q.push(j);
			sa[j] = sa[t] + a[i];
			sb[j] = sb[t] + b[i];
			fa[j][0] = t;
			d[j] = d[t] + 1; 
			for(int k = 1;k <= 19;k ++ )
			fa[j][k] = fa[fa[j][k - 1]][k - 1];
		}
	}
}
void solve()
{
	int n; cin >> n;
	memset(h,-1,sizeof h);idx = 0;
	for(int i = 2;i <= n;i ++ )
	{
		int u,ai,bi; cin >> u >> ai >> bi;
		add(u,i,ai,bi);
		sa[i] = 0,sb[i] = 0,res[i] = 0,d[i] = 0;	
	}
	bfs();
	for(int i = 2;i <= n;i ++ )  cout << res[i] << ' ';
	cout << endl;
	
}

signed main() 
{
	ios;int T; cin >> T;  
	while(T -- ) solve();

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值