1. 程式人生 > 其它 >Codeforces Round #787 (Div. 3) 解題報告

Codeforces Round #787 (Div. 3) 解題報告

A. Food for Animals

題意:商店有a個狗糧,b個貓糧 ,c個通用糧,需要x個狗糧,y個貓糧,問是否能滿足需要
判斷貓和狗能否都被滿足即可
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 main()
{
	ios;
	
	int t;
	cin >> t;
	while(t --)
	{
		int a,b,c,x,y;
		cin >> a >> b >> c >> x >> y;
		
		if(a >= x) ;
		else  c -= x - a;
		if(c < 0 ) 
		{
			cout << "NO" << endl;
			continue;
		}
		if(b + c >= y) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

B. Make It Increasing

題意:給定一個數列a,定義操作:對任意一個a[i] / 2(向下取整),問能夠將這個數列構造成嚴格遞增數列的最小運算元。
從後往前搜一遍,只要a[i] >= a[i + 1] 就進行一次操作。最後判斷一下是否嚴格遞增。
注意:如果a[i] < 0 ,操作會使其變大。
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,a[N];

int main()
{
	ios;
	
	int t;
	cin >> t;
	while(t --)
	{
		cin >> n;
		for(int i = 0;i < n;i ++) cin >> a[i];
		bool f = true;
		LL res = 0;
		for(int i = n - 2;i >= 0;i --)
		{
			while(a[i] && a[i] >= a[i + 1])
			{
				res ++;
				a[i] /= 2;
			}
		}
		for(int i = 1;i < n;i ++) if(a[i] <= a[i - 1]) f = false;
		if(f) cout << res << endl;
		else cout << -1 << endl;
	}
	return 0;
}

C. Detective Task

題意:n個人依次進房間看畫,有一個人偷了畫,按看畫次序問,結果為(1:還在,0:不在, ?:不記得),除小偷外其他人都說的實話,問嫌疑人個數。
如果一個人是小偷,那麼其他人說的都是實話,那麼他前面的人肯定是沒有人說不在的,後面的人肯定沒有說還在的
即對於一個可能的點其前面沒有0,後面沒有1,所以只要找到第一個出現的0的位置r,再找到其第一個為1的位置l,則中間的全是嫌疑人,ans = r - l + 1;

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,a[N],b[N];


int main()
{
	ios;
	
	int t;
	cin >> t;
	while(t --)
	{
		string s;
		cin >> s;
		int l,r;
		for(r = 0;r < s.size() - 1;r ++)
		{
			if(s[r] == '0') break;
		}
		for(l = r;l;l --)
		{
			if(s[l] == '1') break;
		}

		cout << r - l + 1 << endl;
	}
	return 0;
}

D. Vertical Paths

題意:給定一顆樹,問把這顆樹拆成幾條路徑的最小值,並輸出路徑
dfs回溯過程中如果接著往深處走,就是一條新路徑

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,p[N];
int h[N],e[N],ne[N],idx,idxx;

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

map<int,int> mp;
int path[N];
bool st[N];
vector<int > a[ N ];
void dfs(int u,int c)
{
	path[c] = u;
	if(h[u] == -1)
	{
		a[idxx].clear();
		for(int i = 0;i <= c;i ++) a[idxx].push_back(path[i]);
		idxx ++;
		c = -1;
		return ;
	}
	for(int i = h[u];i != -1;i = ne[i])
	{
		int j = e[i];
		dfs(j,c + 1);
	}
}

int main()
{
	ios;
	
	int t;
	cin >> t;
	while(t --)
	{

		int tt;
		idx = idxx = 0;
		mp.clear();
		cin >> n;
		memset(h,-1,(n + 1) * 4);
		for(int i = 1;i <= n;i ++)
		{
			int x;
			cin >> x;
			mp[x] = 1;
			if(x == i)
			{
				tt = i;
				continue;
			}
			add(x,i);
		}

		dfs(tt,0);
		memset(st,0,sizeof st);
		cout << idxx << endl;
		for(int i = 0;i < idxx;i ++)
		{
			int pos;
			for(pos = 0;pos < a[i].size();pos ++) if(!st[a[i][pos]]) break;
			cout << a[i].size() - pos << endl;
			for(;pos < a[i].size(); pos ++) cout << a[i][pos] <<  ' ',st[a[i][pos]] = true;
			cout << endl;
		}
		cout << endl;
	}
	return 0;
}

E. Replace With the Previous, Minimize

題意:給定一個字串,定義操作:

if(s[i] == 'a') s[i] = 'z';
else s[i] -= 1;

並且整個字串中與s[i]相同的字元,都會一起變化,問用k個操作所能得到的字典序最小字串。
大體思路即儘量讓前面的字母變成'a',變不了就儘量往小減。
同時注意到如果一個字元可以變成'a',並且前面的字母都比他小,那麼只需對它操作就可以讓前面全變為'a'。
不難想到字串是這樣的

紅色的結尾是那個第一個不能變成'a'的字元,其前面的只需找到最大的那個對其操作即可。
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;

map<char,char> mp;
bool st[N];
int main()
{
	ios;
	int t;
	cin >> t;
	while(t --)
	{
		int n,k;
		string s;
		cin >> n >> k >> s;
		for(char i = 'a';i <= 'z';i ++) mp[i] = i;
		
		int res = 0;
		for(int i = 0;i < n;i ++)
		{
			if(s[i] - 'a'> k)
			{
				char l = s[i] - k + res;
				char r = s[i];
				if(l > r) break;
				for(int j = 0;j < n;j ++)
				{
					if(s[j] >= l && s[j] <= r)
					{
						s[j] = l;
					}
				}
				break;
			}
			res = max(res,s[i] - 'a');
		}
		for(int j = 0;j < n;j ++) if(s[j] <=  'a' + res) s[j] = 'a';
		cout << s << endl;

	}
	return 0;
}

F. Vlad and Unfinished Business

題意:給定一顆無根樹,以及起點x,終點y。從起點要先經過一系列點然後最終到y,問最短距離。
bfs標記每個節點的父節點並計算距起點的最短距離。
如果想要在一個樹上,要求從根出發,經過若干個點的話,最後回到根,基本想法就是從要經過的點往根遍歷,沒經過一條邊,就要代價 +2,因為一次是往下,第二次是經過了該子樹要經過的點,然後回去
所以這題就套用這個想法,把 y 也作為要經過的點,然後再減去 x 到 y 的距離,就變成最後是在 y 點停下

#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 h[N], e[N * 2], ne[N * 2], idx;
int p[N],d[N];
int n,k,x,y;
void add(int a,int b)
{
	e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

void bfs(int s)
{
	//memset(d,-1,sizeof (int) * (n + 4) ) ;
	memset(p,-1,sizeof (int) * (n + 4));
	p[s] = 0;
	
	queue<PII> q;
	q.push((PII){s,0});
	while(q.size())
	{
		auto t = q.front();
		q.pop();
		int u = t.x;
		d[t.x] = t.y;
		for(int i = h[u];i != -1;i = ne[i])
		{
			int j = e[i];
			if(p[j] == -1)
			{
				p[j] = u;
				q.push({j,d[t.x] + 1});
			}
		}
	}
}
int a[N];
bool st[N];
int main()
{
	ios;
	int t;
	cin >> t;
	while(t --)
	{
		
		cin >> n >> k;
		cin >> x >> y;
		memset(h,-1,sizeof (int) * (n + 4));
		memset(st,0,sizeof (bool) * (n + 4));
		idx = 0;
		
		for(int i = 0;i < k;i ++) cin >> a[i];

		for(int i = 0;i < n - 1;i ++) 
		{
			int a,b;
			cin >> a >> b;
			add(a,b),add(b,a);
		}

		bfs(x);
		
		int res = 0;
		a[k ++] = y;
		st[x] = true;
		for(int i = 0;i < k;i ++)
		{
			int t = a[i];
			while(!st[t])
			{
				st[t] = true;
				t = p[t];
				res += 2;
			}
		}
		
		cout << res - d[y]<< endl;
	}
	return 0;
}