Codeforces Round #787 (Div. 3) A - F 题解
A. Food for Animals
直接找一下本身够不够,然后不够再拿 c
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int main()
{
int t;
cin >> t;
while(t--)
{
int a, b, c, d, e;
cin >> a >> b >> c >> d >> e;
d -= min(d, a);
e -= min(b, e);
if(c >= d + e) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
B. Make It Increasing
因为只能往下除,直接从后往前找就行
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
ll num[maxn], pre[maxn];
int main()
{
int t;
scanf("%d", &t);
ll len = 1ll << 33;
while(t--)
{
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%lld", &num[i]);
int ans = 0;
ll pre = num[n-1] + 1;
int f = 1;
for(int i=n-1; i>=0 && f; i--)
{
while(f && num[i] >= pre)
{
if(num[i] == 0) f = 0;
ans++;
num[i] >>= 1;
}
pre = num[i];
}
printf("%d\n", f ? ans : -1);
}
return 0;
}
C. Detective Task
思维题,说谎的人一定是在转折处,也就是最后一个出现的 1 和最早出现的 0 之间
直接双指针判断一下这个区间有多少个人就行
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
ll num[maxn], pre[maxn];
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
cin >> s;
int l = 0, r = s.length() - 1, len = s.length();
while(l < len && s[l] != '0') l++;
while(r >= 0 && s[r] != '1') r--;
int ans = 0;
ans = l - r + 1;
if(r == -1) ans--;
if(l == len) ans--;
cout << ans << endl;
}
return 0;
}
D. Vertical Paths
这个题直接找路径就行,从叶子结点往上找比较方便
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int top[maxn], vis[maxn], du[maxn];
stack<int>st[maxn];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i=0; i<=n; i++) du[i] = vis[i] = 0;
for(int i=1; i<=n; i++)
{
scanf("%d", &top[i]);
if(i == top[i]) top[i] = 0;
du[top[i]]++;
}
int tp = 0;
for(int i=1; i<=n; i++)
{
if(du[i]) continue;
int now = i;
while(now && vis[now] == 0)
{
st[tp].push(now);
vis[now]++;
now = top[now];
}
tp++;
}
printf("%d\n", tp);
for(int i=0; i<tp; i++)
{
printf("%d\n", st[i].size());
while(st[i].size())
{
int now = st[i].top();
st[i].pop();
printf("%d ", now);
}
printf("\n");
}
tp = 0;
printf("\n");
}
return 0;
}
E. Replace With the Previous, Minimize
类似于记忆化搜索
由于是字典序从小到大,因此从左到右开始找字母,看看能不能压到 a 去,然后记忆一下被压过的每种字母
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 310;
const ll inf = 1e17 + 10;
int alp[maxn];
int main()
{
int t;
cin >> t;
while(t--)
{
int n, k;
cin >> n >> k;
string s;
cin >> s;
if(k >= 26)
{
while(n--) cout << 'a';
cout << endl;
continue;
}
int len = s.length();
for(int i=0; i<300; i++) alp[i] = 0;
alp['a'] = 'a';
for(int i=0; i<len && k; i++)
{
if(alp[s[i]]) continue;
int now = s[i];
while(alp[now] == 0) now--;
int way = s[i] - now;
if(k < way) way = k, now = s[i] - k;
k -= way;
way = alp[now] ? alp[now] : now;
for(int j=now+1; j<=s[i]; j++) alp[j] = way;
}
for(int i=0; i<n; i++)
s[i] = alp[s[i]] ? alp[s[i]] : s[i];
cout << s << endl;
}
return 0;
}
F. Vlad and Unfinished Business
如果想要在一个树上,要求从根出发,经过若干个点的话,最后回到根,基本想法就是从要经过的点往根遍历,没经过一条边,就要代价 +2,因为一次是往下,第二次是经过了该子树要经过的点,然后回去
所以这题就套用这个想法,把 y 也作为要经过的点,然后再减去 x 到 y 的距离,就变成最后是在 y 点停下
这题和天梯赛的 L2-3 一模一样的想法,出题人可能打过天梯赛?
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const int maxn = 2e5 + 10;
int w[maxn], dis[maxn], top[maxn], vis[maxn];
vector<int>gra[maxn];
void bfs(int s)
{
queue<pii>q;
q.push(make_pair(s, 0));
top[s] = s;
while(q.size())
{
pii now = q.front();
q.pop();
int u = now.first;
dis[u] = now.second;
for(int i=0; i<gra[u].size(); i++)
{
int v = gra[u][i];
if(top[v]) continue;
top[v] = u;
q.push(make_pair(v, now.second + 1));
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, m, x, y;
scanf("%d%d%d%d", &n, &m, &x, &y);
for(int i=0; i<m; i++) scanf("%d", &w[i]);
w[m++] = y;
for(int i=1; i<n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
gra[a].push_back(b);
gra[b].push_back(a);
}
bfs(x);
int ans = 0;
vis[x] = 1;
for(int i=0; i<m; i++)
{
int now = w[i];
while(vis[now] == 0)
{
vis[now] = 1;
ans += 2;
now = top[now];
}
}
ans -= dis[y];
printf("%d\n", ans);
for(int i=0; i<=n; i++)
{
vis[i] = top[i] = 0;
gra[i].clear();
}
}
return 0;
}
G. Sorting Pancakes
群友说是个三维 dp? 不懂