A-
题目大意:
方法: 直接模拟
代码:
#include<iostream>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int a,b,c,x,y;
cin>>a>>b>>c>>x>>y;
int temp=0;
if(a-x<0)
{
temp+=x-a;
}
if(b-y<0)
{
temp+=y-b;
}
if(c>=temp)
{
cout<<"YES"<<endl;
}else
{
cout<<"NO"<<endl;
}
}
return 0;
}
B-
题目大意: 给一个序列,可以让其中一数除以2向下取整,使得序列是严格递增,输出最小这样的操作数
方法: 模拟,从后向前遍历(如果从前向后,发现一遍遍历是不行的,因为你不知道当前这个数该除以二除到多小,而从后向前,最后一个数肯定是不动的),如果这个数比后一个数大的话,就除以二向下取整,直到这个数为0。然后判断是否严格递增
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=35;
int a[N];
void solve(void)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int cnt=0;
bool flag=false;
for(int i=n-1;i>=1;i--)
{
while(a[i]>=a[i+1])
{
if(a[i]==0)
{
break;
}
a[i]/=2;
cnt++;
}
if(a[i]>=a[i+1])
{
flag=true;
break;
}
}
if(flag)
{
cout<<-1<<endl;
}else
{
cout<<cnt<<endl;
}
return;
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C-
题目大意:给定一个代表物体的状态的序列,输出可能是小偷的数量
方法: 规律是前无0,后无1,那么就可以被怀疑。可以双指针计算。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=200010;
char s[N];
bool c1[N],c2[N];
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
{
cin>> s+1;
int len=strlen(s+1);
memset(c1,false,sizeof c1);
memset(c2,false,sizeof c2);
bool flag=true;
for(int i=1;i<=len;i++)
{
c1[i]=flag;
if(s[i]=='0')
{
flag=false;
}
}
flag=true;
for(int i=len;i>=1;i--)
{
c2[i]=flag;
if(s[i]=='1')
{
flag=false;
}
}
int cnt=0;
for(int i=1;i<=len;i++)
{
if(c1[i]&&c2[i])
{
cnt++;
}
}
cout<<cnt<<endl;
}
return 0;
}
D-
题目大意: 给一个树,路径只能由父节点到子节点,把这棵树分为若干条路径,输出最小的路径数,并且输出每条路径长度和路径本身
方法: 因为n最多200000,用一个top数组记录每个点的父节点,然后记录每个叶节点,从叶节点向上找路,然后存储每条路径。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=200010;
int f[N];
bool st[N];
bool flag[N];
vector<int> a[N];
vector<int> num;
int main()
{
int t;
cin>>t;
while(t--)
{
memset(st,false,sizeof st);
memset(flag,false,sizeof flag);
int n;
cin>>n;
int root;
for(int i=1;i<=n;i++)
{
cin>>f[i];
if(i==f[i])
{
root = i;
}
st[f[i]]=true;
}
int cnt=0;
for(int i=1;i<=n;i++)
{
int cnt1=0;
if(!st[i]||n==1)
{
int j=i;
while(!flag[j])
{
cnt1++;
a[cnt].push_back(j);
flag[j]=true;
j=f[j];
}
num.push_back(cnt1);
cnt++;
}
}
cout<<cnt<<endl;
for(int i=0;i<cnt;i++)
{
cout<<num[i]<<endl;
for(int j=a[i].size()-1;j>=0;j--)
{
cout<<a[i][j]<<' ';
}
a[i].clear();
num.clear();
cout<<endl;
}
}
return 0;
}
E-
题目大意:给定一个小写字母序列,和操作数,每次操作都可以把序列中每个字母变成前一位,输出操作后字典序最小的序列
方法:字典序最小,那么肯定是从前向后枚举,每次都要尽最大操作数,把当前的字母变得小。
只有小写字母,那么开一个26大小的布尔数组记录该字母是否可以变为前一位,然后将整个序列符合条件的字母变换输出即可
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
int a[N];
bool st[26];
void solve(void)
{
int n,k;
cin>>n>>k;
memset(st,false,sizeof st);
for(int i=1;i<=n;i++)
{
char x;
cin>>x;
a[i]=(int)(x-'a');
}
for(int i=1;i<=n;i++)
{
int j=a[i];
while(k&&j&&!st[j])
{
st[j]=true;j--;
k--;
}
}
for(int i=1;i<=n;i++)
{
int j=a[i];
while(st[j])
{
j--;
a[i]--;
}
}
for(int i=1;i<=n;i++)
{
cout<<(char)(a[i]+'a');
}
cout<<endl;
}
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
F-
题目大意:给一棵树,有起点和终点,还有若干任务点。你要从起点出发,到达所有的任务点(不限顺序),然后最后到达终点,求最小步数
方法: 去任务点是需要 来 和 回 两次,所以是2倍的步数,然后我们和D题一样的思路,我们用一个数组存储一个点的父节点。把任务点和终点都当作“叶子”然后向上走。最后bfs一遍,减去起点到终点的最短路。得到的就是答案。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+10;
int w[N],dis[N],top[N],vis[N];
vector<int> gra[N];
void bfs(int x)
{
queue<PII> q;
q.push({x,0});
top[x]=x;
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({v,now.second+1});
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m,x,y;
cin>>n>>m>>x>>y;
for(int i=0;i<m;i++)cin>>w[i];
w[m] = y;
for(int i=1;i<n;i++)
{
int a,b;
cin>>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 temp=w[i];
while(vis[temp]==0)
{
vis[temp]=1;
ans+=2;
temp=top[temp];
}
}
ans-=dis[y];
cout<<ans<<endl;
for(int i=1;i<=n;i++)
{
vis[i]=top[i]=0;
gra[i].clear();
}
}
return 0;
}
G-
题目大意:给你一个序列,每次都可以把一个数的1移到相邻另一个数上,最终使这个序列不递增
方法: 动态规划。这位大佬讲的不错G题题解