SDUT 2021 Winter Individual Contest - M
A - Block Game
https://vjudge.net/problem/Kattis-blockgame2
题意:
有两堆物品 一次只能拿较少一堆物品的n倍
甲 乙 两人轮流拿,甲先拿,正好拿完一堆的人赢,输出甲的结果
思路
A B 两堆物品 ( 取 A > B)
- A=B || A%B==0 ,甲必赢
- B*2 > A > B : ( A , B ) - > ( A - B , B) 当出现 情况1、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;
}