SDUT 2021 Winter Individual Contest - M --- 2021 / 2 / 21

SDUT 2021 Winter Individual Contest - M

A - Block Game

https://vjudge.net/problem/Kattis-blockgame2

题意:
有两堆物品 一次只能拿较少一堆物品的n倍
甲 乙 两人轮流拿,甲先拿,正好拿完一堆的人赢,输出甲的结果

思路
A B 两堆物品 ( 取 A > B)

  1. A=B || A%B==0 ,甲必赢
  2. B*2 > A > B : ( A , B ) - > ( A - B , B) 当出现 情况1、3 时(循环判断),正好拿完
  3. A > B*2:
    有两种情况:A%B = 1 、A%B ! = 1
    当 A%B = 1 时:甲( A%B+B , B )
    当 A%B ! = 1 时 :甲可以走( A%B , B), 或者走( A%B+B , B ),相当于有一次转输为赢的机会,所以,甲必赢
#include <bits/stdc++.h>
using namespace std;
#define int long long

void judge(int a, int b, int sum)
{
    if((a % b == 0) || (a/b >= 2))
    {
        cout << "win" <<endl;
        return;
    }
    else
        while(b!=1)
        {
            a=a-b;
            swap(a,b);
            sum++;
            if(a/b >= 2)
            {
                cout << (sum%2==1?"lose":"win")<<endl;
                return;
            }
            if(a%b==0)
            {
                cout<<(sum%2==1?"lose":"win")<<endl;
                return;
            }
        }
}

signed main()
{
    ios::sync_with_stdio(false);
    int a, b;
    cin>>a>>b;
    if(b>a) swap(a,b);
    judge(a, b, 0);
    return 0;
}

B - Chess Tournament

https://vjudge.net/problem/Kattis-chesstournament

题意:
判断 点之间的关系是否冲突

思路:
并查集 + 拓扑排序
1 将 有等于 关系的点 看成一个集合(并查集)
2 大于或小于关系的看成有向图,判断是否有环(冲突 : 1 > 3 > 1 )( 拓扑排序 )

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;

struct node
{
    int x,y;
};

int n,m,flag=0;
int fa[N];
vector <int> edge[N];
vector <node> mpp; 
int du[N]={0}; //入度
queue <int> qq;

int fin(int x){
    return fa[x]==x ? x : fa[x]=fin(fa[x]);
}

void sol(int num)
{
    for(int i=0;i<n;i++)
        if(du[i]==0) qq.push(i);

    int nn=qq.size();

    while(!qq.empty())
    {
        int t=qq.front();
        qq.pop();
        for(int i=0;i<edge[t].size();i++)
        {
            if(--du[edge[t][i]]==0)
                qq.push(edge[t][i]),nn++;
        }
    }
    if(nn!=num) flag=1;
}

int main()
{
    cin>>n>>m;
    int x,y;
    char a;
    for(int i=0;i<n;i++)
        fa[i]=i;
    for(int i=0;i<m;i++)
    {
        cin>>x>>a>>y ;
        if(a=='=')
        {
            int fx=fin(fa[x]);
            int fy=fin(fa[y]);
            fa[fx]=fy;
        }
        else if(a=='>')
        mpp.push_back((node){x,y});
        else mpp.push_back((node){y,x});
    }
    for(int i=0;i<mpp.size();i++)
    {
        int fx=fin(fa[mpp[i].x]);
        int fy=fin(fa[mpp[i].y]);
        if(fx==fy) flag=1;
        edge[fx].push_back(fy);
        du[fy]++;
    }

    sol(n);

    if(flag) cout<<"inconsistent"<<endl;
    else cout<<"consistent"<<endl;

    return 0;
}

C - Completing the Square

https://vjudge.net/problem/Kattis-completingthesquare

输入3 个点的 x y坐标
判断第四个点的坐标

好家伙,这种题我都能给码出五十来行,平平无奇乱码小天才?

#include <bits/stdc++.h>
using namespace std;

struct node
{
    int x,y;
} ss[5];

int f1(int x1,int x2,int y1,int y2) {
    return pow(abs(x1-x2),2)+pow(abs(y1-y2),2);
}
int cmp(struct node a,struct node b) {
    return a.x<b.x;
}
int main()
{
    for(int i=0; i<3; i++)
        cin>>ss[i].x>>ss[i].y;
    sort(ss,ss+3,cmp);

    int n1=f1(ss[0].x,ss[1].x,ss[0].y,ss[1].y);
    int n2=f1(ss[0].x,ss[2].x,ss[0].y,ss[2].y);
    int n3=f1(ss[1].x,ss[2].x,ss[1].y,ss[2].y);

    int c1x, c1y,xx, yy;

    if(n1==max(max(n1,n2),n3))
    {
        c1x=ss[0].x-ss[2].x;
        c1y=ss[0].y-ss[2].y;
        xx=ss[1].x+c1x;
        yy=ss[1].y+c1y;
    }
    if(n2==max(max(n1,n2),n3))
    {
        c1x=ss[0].x-ss[1].x;
        c1y=ss[0].y-ss[1].y;
        xx=ss[2].x+c1x;
        yy=ss[2].y+c1y;
    }
    if(n3==max(max(n1,n2),n3))
    {
        c1x=ss[0].x-ss[2].x;
        c1y=ss[0].y-ss[2].y;
        xx=ss[1].x-c1x;
        yy=ss[1].y-c1y;
    }

    cout<<xx<<' '<<yy;

    return 0;
}

G - Millionaire Madness

https://vjudge.net/problem/Kattis-millionairemadness

题意 : 从左上角到右下角 上下左右四个方向 找出一条路 使得 上一个点的高度到 下一个点的高度(负数不计) < x , 求x最小为多少

思路:
优先队列 + bfs
最优方案 先走

#include <bits/stdc++.h>
using namespace std;

const int N=1010;
const int mxn=0x3f3f3f3f;
int mpp[N][N];
int mv[4][2]={1,0,0,1,0,-1,-1,0};
int vis[N][N]={0};
int n,m;

struct node
{
    int x,y;
    int dis;
    bool operator < (const node &other)const {
    return dis > other.dis;
    }
} ;

int bfs()
{
    priority_queue <node> qq;
    qq.push((node){0,0,0});
    while(!qq.empty())
    {
        node t=qq.top();
        qq.pop();
        if(vis[t.x][t.y]) continue;
        vis[t.x][t.y]=1;
        if(t.x==n-1&&t.y==m-1) 
        	return t.dis;

        for(int i=0;i<4;i++)
        {
            int tx=t.x+mv[i][0];
            int ty=t.y+mv[i][1];
            if(tx>=0&&tx<n&&ty>=0&&ty<m&&vis[tx][ty]==0)
            {
                int cd=mpp[tx][ty]-mpp[t.x][t.y];
                if(cd<0) cd=0;
                qq.push((node){tx,ty,max(cd,t.dis)});
            }
        }
    }
    return 0;
}

int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>mpp[i][j];
    cout<< bfs() <<endl;

    return 0;
}

I - Rock Band

https://vjudge.net/problem/Kattis-rockband

题意:
某一乐队有 n 个人 ,每人 m 首歌 (按喜爱值排列)
从中选出 x 首歌
要求: 如果要选 x [ i ][ j ] 那么必须要选 x[ i ][ j-1 ]

纯思维题
分析 :
这里的 m [ ] 是每个人的歌曲序列,

首先 ! 题目给出 M⋅S(我习惯用 n m 表示) ≤ 10^6 , 咳 ,所以这是一个遍历 M S 的两层 for 循环 ,,
所以, 这个 题解遍历一遍这个二维数组就能出来
那么,怎么遍历?
一行一行的找的话 :先把每个人的 m [ 0 ] 加进来,再遍历二维数组,再加,再遍历…最终TLE…

综上,已知,题解为遍历二维 ;按照正常的遍历习惯会TLE
那么,题解马上就出来了,,,反着遍历二维数组 :
先遍历 x [ ] [ 0 ] ,再遍历 x [ ] [ 1 ] ,再遍历 x [ ][ 2 ] …直到 x[ ][ j ],也就是选出的歌曲数目 等于 它的列数 j

咳,第一次能在比赛的时候,把这种纯思维题ac ,当场激动的我拿起六个核桃就喝了一口。hhhhh

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;

vector <int> mpp[N];
set <int> sss;
int st[N],cnt=0;

int main()
{
    ios::sync_with_stdio(0);
    int n,m,x;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
            cin>>x,mpp[i].push_back(x);
    }
    for(int j=0;j<m;j++)
    {
        for(int i=0;i<n;i++)
           sss.insert(mpp[i][j]),st[cnt++]=mpp[i][j];
        int num=sss.size();
         if(num==j+1) break;
    }
    cout<<sss.size()<<endl;
    sort(st,st+cnt);

    cout<<st[0];
    for(int i=1;i<cnt;i++)
        if(st[i]!=st[i-1]) 
        	cout<<' '<<st[i];
    
    cout<<endl;

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值