2023河南萌新联赛第(一)场:河南农业大学_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
C.硬币游戏
考察知识点:博弈
先说结论:若操作一次就能获胜则先手胜,若无论第一次怎么操作,第二次操作都能获胜则后手胜,否则平局
证明:对于上述结论中先手胜和后手胜的局面显而易见,无需证明,对于平局:处于劣势的一方,无论对手怎么操作,只需要复制对手的操作即可保证自己不会输掉,对于此时的另一方,无论怎么操作自己永远也不可能获胜,同时也可以按照上述操作保证自己不会输掉,所以一定会平局
判断一下即可,时间复杂度O(n)
所以只需要找出能够判断胜负的情况即可,其它情况都是平局
AC代码:
#include
#include
#include
#include
#include
using namespace std;
void solve()
{
int n,k;
cin>>n>>k;
string s;
cin>>s;
int cnt=1;
vectorpos;
for(int i=1;ik) puts("Bob");
else if(pos.size()==2&&(pos[0]<=k||pos[1]<=k)) puts("Alice");
else if(pos.size()==3&&pos[1]<=k) puts("Alice");
else if(s == "0101" || s == "1010" || s == "1100" || s == "0110" || s == "0011" || s == "1001") puts("Bob");
else cout<<":(\n";
}
int main()
{
solve();
return 0;
}
D.松鼠回家
使得路径上扣除松果的数量最大的那个点扣除的数量尽可能小,想到用二分来寻找答案,如果用二分得到的数满足的话,就继续往小了找,如果不满足的话,就往大了找
路上所消耗的体力就和边权值是一个意思
对于每一个二分的答案,判断它是否合法,在保证其合法的情况下,找一条体力值尽可能小的路(最短路,这样体力值才能小于h)
用bfs求最短路,如果遇到更短的路径并且去的那个点要扣除的松果小于等于二分得到的数,那么就更新最短路径
AC代码:
#include
#include
#include
#include
#define int long long
using namespace std;
typedef pairPII;
const int N=1e4+10;
int a[N];//扣除松果数量
int n,m,st,ed,h;
vectore[N];
int dist[N],vis[N];
bool bfs(int x)
{
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);
priority_queue,greater>heap;
dist[st]=0;
heap.push({0,st});//把起点放进去
while(heap.size()){
auto t=heap.top();
int d=t.first,ver=t.second;
heap.pop();
if(vis[ver]) continue;
vis[ver]=1;
for(auto v:e[ver]){
int y=v.first,z=v.second;
if(dist[y]>dist[ver]+z&&a[y]<=x){
dist[y]=dist[ver]+z;
heap.push({dist[y],y});
}
}
}
if(dist[ed]<=h) return true;
return false;
}
void solve()
{
cin>>n>>m>>st>>ed>>h;
for(int i=1;i<=n;i++) cin>>a[i];
while(m--){
int x,y,z;
cin>>x>>y>>z;
e[x].push_back({y,z});
e[y].push_back({x,z});
}
int l=1,r=1e7;
while(l
E.动物朋友
AC代码:
#include
#include
#include
#include
#define int long long
using namespace std;
int n,m;
dequeq;
void solve()
{
cin>>n>>m;
int res=0;
int sum=0;
for(int i=0;i>x;
sum+=x;
q.push_back(x);
if(sum==m) res++;
while(sum>=m&&q.size()){
int t=q.front();
sum-=t;
q.pop_front();
if(sum==m) res++;
}
}
cout<
F.松鼠排序
AC代码:
#include
#include
#include
#include
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int res=0;
for(int i=1;i<=n;i++){
while(a[i]!=i){
swap(a[i],a[a[i]]);
res++;
}
}
cout<
G.Reverse
AC代码:
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
void solve()
{
int n;
cin>>n;
string s;
cin>>s;
s+='0';
int cnt=0;
priority_queueq;
for(int i=0;i<=n;i++){
if(s[i]=='0') {
q.push(cnt);
cnt=0;
}
else if(s[i]=='1') cnt++;
}
int res=0;
if(q.size()){
int t=q.top();
q.pop();
res+=t;
}
if(q.size()){
int t=q.top();
q.pop();
res+=t;
}
cout<
H.迷宫探险
用bfs求最短路,先将起点放入队列
然后一层层拓展,遇到道路,则向四周拓展一步
遇到弹射器,则四个方向拓展x距离,只需看最后是否越出边界或者遇到墙壁 、
注意之前是通过标记位置表示已经走过,而已经走过则表示到这是最短距离
但是这里有弹射,所以走过并不代表是最短距离,所以这里比较和起点之间的距离大小
AC代码:
#include
#include
#include
#include
//#define int long long,以后不要轻易用这个了
using namespace std;
typedef pairPII;
const int N=3010;
char s[N][N];
int d[N][N];
int len[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int n,m,k;
void bfs(){
queueq;
memset(d,0x3f,sizeof d);
d[1][1]=0;
q.push({1,1});
while(q.size()){
auto t=q.front();
q.pop();
if(s[t.first][t.second]=='.'){
for(int i=0;i<4;i++){
int x=t.first+dx[i],y=t.second+dy[i];
if(x&&y&&x<=n&&y<=m&&s[x][y]!='#'&&d[x][y]>d[t.first][t.second]+1){
d[x][y]=d[t.first][t.second]+1;
q.push({x,y});
}
}
}
else{
for(int i=0;i<4;i++){
int x=t.first+dx[i]*len[t.first][t.second];
int y=t.second+dy[i]*len[t.first][t.second];
if(x>=1&&y>=1&&x<=n&&y<=m&&s[x][y]!='#'&&d[x][y]>d[t.first][t.second]){
d[x][y]=d[t.first][t.second];
q.push({x,y});
}
}
}
}
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
}
}
cin>>k;
while(k--){
int x,y,z;
cin>>x>>y>>z;
len[x][y]=z;
}
bfs();
if(d[n][m]==0x3f3f3f3f) cout<<-1<
J.合唱比赛
AC代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
void solve()
{
int n;
cin>>n;
vectora;
int sum=0;
for(int i=0;i>x;
a.push_back(x);
sum+=x;
}
sort(a.begin(),a.end());
int len=a.size();
int sum1=sum-a[len-1];
printf("%.6f ",(double)sum1/(n-1));
int sum2=sum-a[0];
printf("%.6f\n",(double)sum2/(n-1));
}
signed main()
{
solve();
return 0;
}
K.以撒和隐藏房间
AC代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
const int N=1010;
char s[N][N];
int n,m;
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
}
}
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]!='0') continue;
int normal=0,boss=0;
if(i-1>=1){
if(s[i-1][j]=='1') normal++;
else if(s[i-1][j]=='2') boss++;
}
if(i+1<=n){
if(s[i+1][j]=='1') normal++;
else if(s[i+1][j]=='2') boss++;
}
if(j-1>=1){
if(s[i][j-1]=='1') normal++;
else if(s[i][j-1]=='2') boss++;
}
if(j+1<=m){
if(s[i][j+1]=='1') normal++;
else if(s[i][j+1]=='2') boss++;
}
if(normal==3&&boss==0) res++;
}
}
if(res){
puts("YES");
cout<
L.中位数
树状数组+二分
AC代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include