SDNU_ACM_ICPC_2022_Winter_Practice_6th [个人赛]

A

A - Booby Prize

题意:给出n个不同的整数,问第二大的整数是第几个整数。

思路:结构体排序

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=2e5+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
struct node
{
    int num,s;
}a[maxx];
bool cmp(node a,node b)
{
    return a.s<b.s;
}
void solve()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        a[i].num=i;
        scanf("%d",&a[i].s);
    }
    sort(a+1,a+n+1,cmp);
    printf("%d",a[n-1].num);
}
int main() 
{
    int _t=1;

    //scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

E

E - Takahashi Tour

题意:给定一张图,n个点,n-1条边,优先遍历与当前点相连中编号最小的点,没有点可以允许返回。求遍历所有点的顺序。

思路:对每个点可以到达的点进行排序,回溯时记得输出。

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=2e5+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
vector<int>v[maxx];
bool vis[maxx];
void dfs(int x)
{
    vis[x]=1;//标记走过
    printf("%d ",x);//第一次走到时
    for(int i=0;i<v[x].size();i++)//遍历该点可到达的点
    {
        int nex=v[x][i];
        if(!vis[nex])
        {
            vis[nex]=1;
            dfs(nex);
            printf("%d ",x);//回溯也要走一遍
        }
    }
}
void solve()
{
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        v[a].push_back(b);//a可以到达的点
        v[b].push_back(a);//b可以到达的点
    }
    for(int i=1;i<=n;i++)//对每个点可到达的点进行排序
    {
        sort(v[i].begin(),v[i].end());
    }
    dfs(1);
    
}
int main() 
{
    int _t=1;

    //scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

F

F - Arbitrage

题意:给你n种货币,m种货币之间的汇率关系。让你判断这些货币通过这些汇率关系能不能增值。

思路:因为给的是货币名称,我们可以先用map将货币关系转化成一幅图,然后用佛洛依德算法。

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=2010;
const int inf=0x3f3f3f3f;
using namespace std;
int n,m,t;
map<string,int>q;
double mp[35][35];
void solve()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
        {
            string s;
            cin>>s;
            q[s]=i;
            mp[i][i]=1;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            string from,to;
            double w;
            cin>>from>>w>>to;
            mp[q[from]][q[to]]=w;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                for(int k=1;k<=n;k++)
                {
                    mp[j][k]=max(mp[j][k],mp[j][i]*mp[i][k]);//汇率关系 : j -> k = j -> i * i -> k
                }
            }
        }
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            if(mp[i][i]>1) //最后看i->i是否大于1
            {
                flag=1;
                break;
            }
        }
        printf("Case %d: %s\n",++t,flag? "Yes":"No");
    }
    
}
int main() 
{
    int _t=1;

    //scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

G

G - Reorder Cards

题意:给定h*w的矩阵,其中n张牌写有数字,给出这n张牌的坐标。若一行或一列中没有带数字的牌就删掉这一行或这一列,执行完所有操作后,这些带数字牌的坐标是多少。

思路:答案是带有数字的卡牌的相对坐标,并且我们只关注行列是否有带数字的牌,不关注卡牌的数量。所有我们可以离散化所有带数字卡牌的坐标,二分查找卡片的相对坐标即为答案。

unique函数

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=1e9+10;
const int inf=0x3f3f3f3f;
using namespace std;
struct node
{
    int x,y;
}a[100010];
vector<int>vx,vy;
int h,w,n;
int get(int x,vector<int> &v)
{
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void solve()
{
    scanf("%d %d %d",&h,&w,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d",&a[i].x,&a[i].y);
        vx.push_back(a[i].x);
        vy.push_back(a[i].y);
    }
    sort(vx.begin(),vx.end());
    sort(vy.begin(),vy.end());
    vx.erase(unique(vx.begin(),vx.end()),vx.end());
    vy.erase(unique(vy.begin(),vy.end()),vy.end());
    for(int i=1;i<=n;i++)
    {
        printf("%d %d\n",get(a[i].x,vx),get(a[i].y,vy));
    }
}
int main() 
{
    int _t=1;

    //scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

I

I - Stronger Takahashi 

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=510;
const int inf=0x3f3f3f3f;
using namespace std;
int h,w;
char mp[maxx][maxx];
int cost[maxx][maxx];
int dir[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
struct P
{
    int x,y;
};
deque<P>q;
bool check(int x,int y)
{
    if(x<=0||x>h||y<=0||y>w) return false;
    return true;
}
void bfs(int sx,int sy)
{
    memset(cost,0x3f,sizeof(cost));
    cost[1][1]=0;
    q.push_front({sx,sy});
    while(!q.empty())
    {
        P now=q.front();q.pop_front();
        for(int i=0;i<4;i++)
        {
            int nx=now.x+dir[i][0];
            int ny=now.y+dir[i][1];
            if(!check(nx,ny)) continue;
            if(mp[nx][ny]=='.')
            {
                if(cost[nx][ny]>cost[now.x][now.y])
                {
                    cost[nx][ny]=cost[now.x][now.y];
                    q.push_front({nx,ny});
                }
            }
            else
            {
                for(int j=-1;j<=1;j++)
                {
                    for(int k=-1;k<=1;k++)
                    {
                        int dx=nx+j;
                        int dy=ny+k;
                        if(!check(dx,dy)) continue;
                        if(cost[dx][dy]>cost[now.x][now.y]+1)
                        {
                            cost[dx][dy]=cost[now.x][now.y]+1;
                            q.push_back({dx,dy});
                        }

                    }
                }
            }
        }
    }
}
void solve()
{
    scanf("%d %d",&h,&w);
    for(int i=1;i<=h;i++)
    {
        for(int j=1;j<=w;j++)
        {
            cin>>mp[i][j];
        }
    }
    bfs(1,1);
    printf("%d\n",cost[h][w]);
}
int main() 
{
    int _t=1;

    //scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

J

J - Challenging Cliffs

题意:给定n座山的高度hi,当h_{i+1}>=h_{i}时,难度会增加。问如何安排这些山使得第一座山和最后一座山的高度差尽可能小的同时难度最大。

思路:首先要使两侧山的高度差最小,需要找出两座高度最接近的两座山h_{i}h_{i+1}放在两侧。然后要使难度最大,所以排序后山高度要最多的递增。即h_{i},h_{i+2}...h_{n},h_{1},h_{2}...h_{i+1}

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=2e5+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
ll a[maxx];
ll c[maxx];
void solve()
{
    scanf("%d",&n);
    int mi=inf,ii=-1;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(int i=2;i<=n;i++)
    {
        c[i]=a[i]-a[i-1];
        if(c[i]<mi)
        {
            mi=c[i];
            ii=i;
        }
    }
    printf("%lld ",a[ii-1]);
    for(int i=ii+1;i<=n;i++) printf("%lld ",a[i]);
    for(int i=1;i<ii-1;i++) printf("%lld ",a[i]);
    printf("%lld ",a[ii]);
    printf("\n");
}
int main() 
{
    int _t=1;

    scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

L

L - Deleting Divisors

题意:A和B玩游戏,开始时正整数n,每轮可以让当前数减去一个因子(除1和当前数外的因子),最后无法进行操作的玩家输掉,A先手,问谁会取胜。

思路:①当n为奇数时,A只能减去一个奇数因子D,设n=r*D,B得到的n-D一定是一个偶数且含有奇数因子,因为(r-1)*D!=2^{k},(r-1)*D一定含有奇数因子。此时B减去奇数因子返回奇数给对手,A只能再减去奇数因子返回带有奇数因子的偶数给B。所以A总是拿到奇数,又因为质数总是奇数,所以输的是A。(但特例2也是质数,但B拿到的是含有奇数因子的偶数,所以不存在这种情况。)

②当n为偶数且含有奇数因子时,同上,A胜。

③当n为偶数且没有奇数因子时,即n=2^{k},A只能减去2^{k1},B得到2^{k}-2^{k1}仍为偶数,2^{k1}(2^{k-k1}-1),若(2^{k-k1}-1)为奇数,A就输了。所以A只能让k1 = k - 1,B同理。所以每次让n减为原来的一半,只需考虑k的奇偶即可:当k为奇数时,最后A拿到2,B胜;当k为偶数时,最后B拿到2,A胜。

参考文章

#include <stdio.h>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <cstdlib>
#include <set>
#include <queue>
#define PI pair<int,int>
#define lowbit(x) x&(-x)
#define endl '\n'
#define sf(x) scanf("%d",&x)
#define rep(i,x) for(i=0;i<(x);i++)
#define gen(x) x##_
typedef long long ll;
const int maxx=1e9+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
void solve()
{
    scanf("%d",&n);
    if(n&1) cout<<"Bob\n";
    else 
    {
        int num=0;
        while(n%2==0)
        {
            num++;
            n/=2;
        }
        if(n!=1) cout<<"Alice\n";
        else
        {
            if(num&1) cout<<"Bob\n";
            else cout<<"Alice\n";
        }
    }
}
int main() 
{
    int _t=1;

    scanf("%d",&_t);
    while(_t--)
    {
        solve();
    }
    system("pause");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值