0
点赞
收藏
分享

微信扫一扫

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

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

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'&&c<='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&&y==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'&&c<='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'&&c<='9'){a=a*10+c-'0';c=getchar();}return a*b;}
string s;
bool faultchar(char c){
    if(c>='0'&&c<='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'&&s[i]<='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'&&c<='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'&&c<='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].l&&x<=o[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'&&c<='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'&&c<='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 条评论