0
点赞
收藏
分享

微信扫一扫

信大第三届超越杯团体赛题解

和谐幸福的人生 2022-05-01 阅读 68
算法

A 红红找蓝蓝

题解

宽搜bfs,定义状态{x,y,d,Dir}表示:到(x,y)点拐了d次弯,上一次的方向为Dir

与最短路不同的是,我们从一个点出发要把一个方向上的所有点加入队列,因为这个方向上所有点的拐弯数都只是+1,为了维护先搜到的点拐弯数越少,就要把一个方向上所有点加入队列。

注意不能省略vis[x][y],是为了剪除大量没有意义的搜索,并且如果不加的话会爆空间,别问我为啥知道

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
int n,ax,ay,bx,by;
bool canarrive;
char m[110][110],t;
bool vis[110][110];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
void Read(){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
t=getchar();
while(t=='\n'||t==' ')t=getchar();
m[i][j]=t;
if(t=='A'){
ax=i;ay=j;
}
if(t=='B'){
bx=i;by=j;
}
}
}
}
struct node{
int x,y,d,Dir;//意义为:走到(x,y)拐了d次弯,上一次的方向是Dir
node(int xx,int yy,int dd,int ddd){
x=xx;y=yy;d=dd;Dir=ddd;
}
node(){}
};
bool check(int x,int y){
if(x<1||x>n||y<1||y>n||m[x][y]=='x')return false;
return true;
}
void bfs(){
memset(vis,0,sizeof vis);
queue<node> q;
node u;
int x,y,d;
q.push(node(ax,ay,-1,-1));
vis[ax][ay]=1;
while(!q.empty()){
u=q.front();q.pop();
x=u.x;y=u.y;d=u.d;
if(x==bx=by){
printf("%d\n",d);
canarrive=1;
return;
}
for(int i=0;i<4;++i){
if(i==u.Dir)continue;
int vx=x+dir[i][0];
int vy=y+dir[i][1];
while(check(vx,vy)){
if(!vis[vx][vy]){
vis[vx][vy]=1;
q.push(node(vx,vy,d+1,i));
}
vx+=dir[i][0];vy+=dir[i][1];
}
}
}
printf("-1\n");
}
int main(){
int T=R();
while(T--){
n=R();
Read();
bfs();
}
return 0;
}

B 红红蓝蓝在争论

题解

贪心+双指针扫描,我们把题目做两遍,把0变成1,以及把1变成0(下面只描述0变1)

很容易想到我们要变肯定是把相邻的0变成1,这样满足贪心策略

那我们把所有0的下标用vector存起来,l,r指针分别指向m个需要改变的0

那么就可以更新答案为 ans=max(ans,v[r+1]-v[l-1]-1)

l,r指针不断向右++

对于0的个数不足m个以及扫描边界再特殊处理一下就OK了

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
int n,m,ans,s_len;
string s;
vector<int> v[2];
void init(){
ans=0;
v[0].clear();
v[1].clear();
}
void work(int k){
int v_num=v[k].size();
if(v_num<=m){
ans=s_len;
return;
}
int l=0,r;
for(int i=0;i<v_num;++i){
if(i+1<=m){
ans=max(ans,v[k][i+1]);
}else{
r=i-1;
break;
}
}
l++;r++;
while(r<=v_num-1){
if(r==v_num-1) ans=max(ans,s_len-v[k][l-1]);
else ans=max(ans,v[k][r+1]-v[k][l-1]-1);
l++;r++;
}
}
int main(){
int T=R();
while(T--){
init();
n=R();m=R();
cin>>s;
s_len=s.size();
for(int i=0;i<s_len;++i){
v[s[i]-'0'].push_back(i);
}
work(1);
work(0);
printf("%d\n",ans);
}
return 0;
}

C 合法的 IP 地址

 

 题解

纯模拟,注意细节判断

给几种不合法的情况:

1..1.1        (这种容易出错)

1.1.1.1.

1x.1.1.1

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
string s;
bool faultchar(char c){
if(c>='0''9'||c=='.')return false;
return true;
}
bool work(){
int s_len=s.size();
char c;
int num_cnt=0;
int a[5];
memset(a,-1,sizeof a);
for(int i=0;i<s_len;++i){
if(faultchar(s[i]))return false;
if(s[i]>='0''9'){
if(a[num_cnt]==-1)a[num_cnt]=0;
a[num_cnt]=a[num_cnt]*10+s[i]-'0';
}else{
num_cnt++;
}
}
if(num_cnt!=3)return false;
if(a[0]<=0||a[0]>255)return false;
for(int i=1;i<4;++i){
if(a[i]<0||a[i]>255)return false;
}
return true;
}
int main(){
int T=R();
while(T--){
cin>>s;
if(work()){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}

D 石头剪刀布

题解

真·签到题

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
int main(){
int T=R();
while(T--){
int n=R()%3;
switch(n){
case 0: printf("Scissors\n");break;
case 1: printf("Paper\n");break;
case 2: printf("Rock\n");break;
}
}
return 0;
}

G Jump

题解

线段树+递推,对于每个位置先求出到达它的最大经验值,再把这个值加到它所能到达的区间的线段树里去,然后对于后面的位置,单点求线段树最大值再加上自己的经验值即为 f[i] 。

线段树区间修改,单点询问。注意线段树空间要开4*n

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
struct Tree{
ll l,r,d;
}o[200010*4];
ll n,m,ans,a[200010];
void build(ll i,ll L,ll R){
o[i].l=L;o[i].r=R;
o[i].d=-0x3f3f3f3f;//附加性质初始化
if(L==R)return;
ll mid=(L+R)>>1;
build(i<<1,L,mid);
build(i<<1|1,mid+1,R);
}
void Add2(ll i,ll L,ll R,ll d){
if(R<o[i].l||L>o[i].r)return;
if(L<=o[i].l&&o[i].r<=R){
o[i].d=max(o[i].d,d);return;
}
Add2(i<<1,L,R,d);
Add2(i<<1|1,L,R,d);
}
void Ask2(ll i,ll x){
if(x<o[i].l||x>o[i].r)return;
if(x>=o[i].lo[i].r){
ans=max(ans,o[i].d);
}
if(o[i].l==o[i].r)return;
Ask2(i<<1,x);
Ask2(i<<1|1,x);
}
int main(){
n=R();
build(1,1,n);
for(ll i=1;i<=n;++i)a[i]=R();
ll l,r;
for(ll i=1;i<=n-1;++i){
l=R();r=R();
ans=-0x3f3f3f3f;
Add2(1,l,r,a[i]);
Ask2(1,i+1);
a[i+1]=ans+a[i+1];
}
printf("%lld",a[n]);
return 0;
}

K 最小整数问题

 题解

真·水题

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
string s;
int main(){
int T=R();
while(T--){
cin>>s;
sort(s.begin(),s.end());
int x=0;
while(s[x]=='0')x++;
swap(s[0],s[x]);
cout<<s<<'\n';
}
return 0;
}

J Kabayashi And Three consciousness

 

题解

模拟+gcd

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0''9'){a=a*10+c-'0';c=getchar();}return a*b;}
ll p,q;
ll cnt,ans[1000100];
ll gcd(ll a,ll b){
return (!b?a:gcd(b,a%b));
}
int main(){
p=R();q=R();
ll g=gcd(p,q);
p/=g;q/=g;
swap(p,q);
do{
swap(p,q);
ll zhengshu=p/q;
ans[++cnt]=zhengshu;
p-=q*zhengshu;
g=gcd(p,q);
p/=g;q/=g;
}while(p!=1);
ans[++cnt]=q;
printf("%lld\n",cnt);
for(ll i=1;i<=cnt;++i){
printf("%lld ",ans[i]);
}
return 0;
}
举报

相关推荐

0 条评论