A. Elections
链接:A
题意:给三个数,输出每个数要变成最大值至少要加的值
做法:用max模拟一下就好
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while (t--){
int a,b,c;cin>>a>>b>>c;
cout<<max(max(b,c)-a+1,0)<<" "<<max(max(a,c)-b+1,0)<<" "<<max(max(a,b)-c+1,0)<<endl;
}
}
B. Make it Divisible by 25
链接:B
题意:给一串数,去掉任意数后使其变为25的倍数,求最少去掉几个数
做法:数学规律+暴力枚举。发现规律25的倍数末尾必为00,25,50,75,故暴力枚举、用双指针往后找越接近末尾的子序列,去掉的数=右指针到末尾的数+左右指针中间的数,再取最小值即可
#include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
string s[] = {"00","25","50","75"};
signed main(){
IOS
//for (int i=25;i<=100000;i+=25) cout<<i<<endl;
int t;cin>>t;
while (t--){
string ss;cin>>ss;
int len = ss.length();
int ans = INF;
for (int i=0;i<4;i++){
int l = -1,r = -1;
for (int k=0;k<ss.size();k++){
if (ss[k]==s[i][1]){
r = k;
}
}//右指针先找末尾数的位置
if (r!=-1){
for (int k=0;k<ss.size()&&k<r;k++){
if (ss[k]==s[i][0]){
l = k;
}
}
}
//cout<<"l = "<<l<<" r = "<<r<<endl;
if (l!=-1&&r!=-1) {
ans = min(len-r-1+r-l-1,ans);
}
}
cout<<ans<<endl;
}
}
C. Save More Mice
链接:C
题意:x坐标轴上,一只猫在零点,k只老鼠在正坐标轴上,n坐标点有一个洞。每个时间单位可以让一只老鼠向右移一格,同时猫也向右一格,若猫移到的坐标上有一只老鼠,这只老鼠就会被吃。老鼠进洞就不会被吃。问有多少只不会被吃。
做法:经典贪心+模拟。对老鼠坐标排序,越接近洞的老鼠先走,累计时间为前几只老鼠到洞的距离之和,当前老鼠到洞的距离<累计时间即不会被吃
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
int main(){
IOS
int t;cin>>t;
while (t--){
int n,k;cin>>n>>k;
int x[k+1];
int ans = 0,sum = 0,c = 0;
for (int i=1;i<=k;i++) cin>>x[i];
sort(x+1,x+k+1);
for (int i=k;i>=1;i--){
int t = n - x[i];
if (c<x[i]) ans++;
else break;
c += t;
}
cout<<ans<<endl;
}
}
D1. All are Same
链接:D1
题意:给偶数个数,选择一些数减少k的整数倍,使所有数相等,问k的最大值(k任意大则输出-1)
做法:差分+数学 。所有数相等=差分为0,k为最大的使所有差分数组能够被整除的数。故排序后去重求差分的最大公约数即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
signed main(){
int t;cin>>t;
while (t--){
int n;cin>>n;
vector<int>a;
for (int i=1;i<=n;i++){
int x;cin>>x;
a.push_back(x);
}
if (n==1){
cout<<0<<endl;
continue;
}//只有一个数 直接输出0
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end()),a.end());
if (a.size()==1){//去重后只有一个数,说明所有数相等,k取任意大,输出-1
cout<<-1<<endl;
continue;
}
int x = a[1] - a[0];
for (int i=2;i<a.size();i++){
x = gcd(a[i]-a[i-1],x);
}
cout<<x<<endl;
}
}
E. Gardener and Tree
链接:E
题意:给一个无向树图,有n个结点n-1条边,进行k次操作,每次操作删去叶子结点。问剩下几个结点
做法:拓扑+bfs。将入度为0的为叶子结点入队,从叶子结点往上模拟删去操作即可
#include <bits/stdc++.h>
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N = 4e5 + 7;
int n,k;
int du[N];
bool vis[N];
void Init(){
for (int i=1;i<=n;i++) du[i] = 0;
for (int i=1;i<=n;i++) vis[i] = 0;
}
int main(){
int t;cin>>t;
while (t--){
cin>>n>>k;
Init();
vector<int>v[n+1];
for (int i=0;i<n-1;i++){
int ui,vi;cin>>ui>>vi;
du[ui]++,du[vi]++;
v[ui].push_back(vi),v[vi].push_back(ui);
}
if (n==1){
cout<<0<<endl;
continue;
}
queue<PII>q;
//第一关键词存叶子结点 第二关键词存操作值
for (int i=1;i<=n;i++){
if (du[i]==1) q.push({i,1});
}//将叶子结点入队
while (!q.empty()){
auto it = q.front();
q.pop();
if (vis[it.x]) continue;
vis[it.x] = 1;//入队的叶子进行标记
for (auto i:v[it.x]){//遍历和它连接的点
du[i]--;//该叶子删去所以du--
if (du[i]==1){//度为1说明其变成新叶子
if (it.y+1<=k){//当前操作值+1比k小 说明可以删去
q.push({i,it.y+1});
}
}
}
}
int ans = 0;
for (int i=1;i<=n;i++)
if (!vis[i]) ans++;
cout<<ans<<endl;
}
}
其他题待补充