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;
}