文章目录
一、A. Food for Animals?
思路 因为猫粮和狗粮是固定的,所以先让猫吃猫粮,狗吃狗粮,然后如果猫粮或者狗粮不够的话,再让他们吃共同粮,判断一下共同的粮食够不够吃
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 1100,mod = 1000000007;
void solve()
{
int a,b,c,x,y; cin >> a >> b >> c >> x >> y;
int q = max(x - a,(int)0);
int w = max(y - b,(int)0);
if(q + w <= c)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
signed main()
{
ios; int t; cin >> t;
while( t -- ) solve();
return 0;
}
二、B - Make It Increasing
思路 因为每次都是a[i]除以2 所以,越除越小,所以从后面往前面遍历,满足贪心
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 1100,mod = 1000000007;
int a[N];
void solve()
{
int n; cin >> n;
for(int i = 1;i <= n;i ++ )
{
cin >> a[i];
}
int ans = 0;
for(int i = n - 1;i >= 1;i -- )
{
if(a[i] < a[i + 1]) continue;
if(a[i] == 0 || a[i + 1] == 0)
{
cout << "-1" << endl;
return;
}
while(a[i] >= a[i + 1])
{
a[i] /= 2;
ans++;
}
}
cout << ans << endl;
}
signed main()
{
ios; int t; cin >> t;
while( t -- ) solve();
return 0;
}
三、C - Detective Task
思路: 因为只有一个小偷,所以可以枚举每一个人,假设第i个人是小偷,那后面的人只能说实话,后面的人只能是问号或者0,第i个人前面的人也是得说实话所以只能是问号或者1,这样这个人才有可能是小偷
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 2e5 + 100,mod = 1000000007;
int s1[N],s0[N],s[N];// 预处理一下
char a[N];
void solve()
{
cin >> a + 1;
int q = strlen(a + 1);
for(int i = 1;i <= q;i ++ )
{
if(a[i] == '1')
{
s1[i] = s1[i - 1] + 1;
s0[i] = s0[i - 1];
s[i] = s[i - 1];
}
else if(a[i] == '0')
{
s1[i] = s1[i - 1];
s0[i] = s0[i - 1] + 1;
s[i] = s[i - 1];
}
else
{
s1[i] = s1[i - 1];
s0[i] = s0[i - 1];
s[i] = s[i - 1] + 1;
}
}
int ans = 0;
for(int i = 1;i <= q;i ++ )
{
if(s[i - 1] + s1[i - 1] == i - 1 && s[q] - s[i] + s0[q] - s0[i] == (q - i)) ans ++;
//如果前面全是1和问号,后面全是0和问号,那i就有可能是小偷
}
cout << ans << endl;
}
signed main()
{
ios; int t; cin >> t;
while( t -- ) solve();
return 0;
}
四、D - Vertical Paths
思路: 这个要路径最少的话,就看这颗树有多少个叶子节点,就有多少条路径,遍历一遍树存一下每个节点的父节点和叶子节点,每个节点只能用一次,然后再遍历叶子节点往上找即可
#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 2e5 + 100,mod = 1000000007;
int pre[N];
vector<int> res[N],ans;
bool st[N],st2[N];
vector<int> num;
void dfs(int u,int fa) // 无向图,但是我们只走一遍,fa判断是否重复走了
{
for(int i = 0;i < res[u].size();i ++ )
{
int j = res[u][i];
if(j == fa) continue;
dfs(j,u);
pre[j] = u;
}
if(res[u].size() == 1 && !st2[u])
{
st2[u] = true;
ans.pb(u);
}
}
void solve()
{
int n; cin >> n;
int root;
read(i,1,n)
{
int x;
cin >> x;
if(x == i)
root = i;
res[x].pb(i);
res[i].pb(x);
}
if(n == 1)
{
cout << "1" << endl << "1" << endl << "1" << endl;
}
else
{
dfs(root,-1);
cout << ans.size() << endl;
for(int i = 0;i < ans.size();i ++ )
{
int u = ans[i]; // 往上面找
num.pb(u);
st[u] = true;
while(1)
{
u = pre[u];
if(u == 0) break;
if(st[u]) break;
else
{
st[u] = true;
num.pb(u);
}
}
cout << num.size() << endl;
for(int i = num.size() - 1;i >= 0;i -- )
cout << num[i] << ' ';
cout << endl;
num.clear();
}
}
for(int i = 0;i <= n;i ++ )
{
st[i] = false;
st2[i] = false;
res[i].clear();
pre[i] = 0;
}
ans.clear();
}
int main()
{
ios; int t; cin >> t;
while( t -- ) solve();
return 0;
}
五、E - Replace With the Previous, Minimize
思路: 这道题要求字典序最小,所以我们要从左到右判断每一个字符是否能到 ‘a’,如果该字符能到’a’,那后面的比该字符小的也全部能到’a’,当我们遍历到一个不符合条件的也就是说 k 次满足不了该字符变成 ‘a’,那我们就不用往后面遍历了,因为我们要满足字典序最小 所以最后多余的几次 k - w次就全部给这个字符 (w是使得前面的字符能够减到’a’需要的最大次数),就是让最这个字符减去(k - w)次
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 2e5 + 100,mod = 1000000007;
void solve()
{
int n,k; cin >> n >> k;
string s; cin >> s;
char op = 'a',w = s[0],op2 = 'a',u = 'a';
string res;
int cnt = 0;
for(int i = 0;i < n;i ++ )
{
if((int)(s[i] - 'a') <= k) // 都能变成a
{
w = max(s[i],w);// 找到一个能够到'a',最大的s[i]
}
else
{
if(i == 0)// 特判一下第一个字符,第一个字符到不了a,那就把k次全部给第一个字符
{
op = (char)((s[i] - 'a' - k) + 'a');
break;
}
cnt = w - 'a';
cnt = k - cnt; // 最多减几次
int e = (int)(s[i] - 'a' - cnt);
op2 = (char)(e + 'a'); // 剩下的次数的全部给这个字符,使得这个字符减到了op2
u = s[i];
break;
}
}
for(int i = 0;i < n;i ++ )
{
if(s[i] <= w)
res += min(op,s[i]);
else
{
if(s[i] <= u)
res += min(op2,s[i]);
else
res += s[i];
}
}
cout << res << endl;
}
signed main()
{
ios; int t; cin >> t;
while( t -- ) solve();
return 0;
}
六、F. Vlad and Unfinished Business
思路: 先dfs遍历一遍树,存一下节点的前驱节点,然后标记一下从x到y这条路径中的所有的点,再遍历每一个需要去的节点的位置,让这个节点往上走,找到第一个被标记的节点,详细在代码中
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()
#define endl '\n'
using namespace std;
const int N = 2e5 + 100,mod = 1000000007;
vector<int> res[N];
int a[N],pre[N],n,k,x,y,ans = -1;
bool st[N];
void dfs(int u,int fa,int len)
{
if(u == y && ans == -1)
{
ans = len;
}
read(i,0,res[u].size() - 1)
{
int j = res[u][i];
if(fa == j) continue;
dfs(j,u,len + 1);
pre[j] = u;
}
}
void solve()
{
scanf("%lld%lld%lld%lld",&n,&k,&x,&y);
for(int i = 1;i <= k;i ++ ) scanf("%lld",&a[i]);
read(i,1,n - 1)
{
int u,v;scanf("%lld%lld",&u,&v);
res[u].pb(v);
res[v].pb(u);
}
dfs(x,-1,0); // 先让x走到y;走了几步,因为存的是无向图,所以可以说这里面把x当成根了
int q = y;
st[y] = true; // 标记一下从x到y的所有路径
while(q != x)
{
q = pre[q];
st[q] = true;
}
for(int i = 1;i <= k;i ++ ) // 遍历每一个节点
{
int d = 0;
int q = a[i]; // 往上找,找到第一个被标记过的节点就结束
//因为被标记过的节点,之前一定会被走
while(1)
{
if(st[q]) break;
st[q] = true;
q = pre[q];
d++;
}
ans += (2 * d);// 来回是两步,所以就 d * 2
}
printf("%lld\n",ans);
for(int i = 0;i <= n;i ++ )
{
res[i].clear();
st[i] = false;
pre[i] = 0;
}
ans = -1;
}
signed main()
{
int t; scanf("%lld",&t);
while( t -- ) solve();
return 0;
}
总结
这个cf 打的不好,有点瓜皮了,自己,还是太菜