大一省赛选拔赛(2019.4.20)

本次比赛共8题,本文附AC代码和题目链接。
这次先写H题和G题,因为比赛的时候这两题我没写出来…

———————————————————————————————————————————————

H题 nefu 1818 库特的字符串

这题要想清楚字符变换的要求,设第一个字符串为a,第二个字符串为b,我们先列一个表格研究一下字符合成的规律:

情况编号
a中某个字符 A B A B
b中某个字符 B B A A
合成后的字符 A B A A
如果要改变合成后的字符串,只能改变a字符串,如何变换? 将a字符串的’A’与其之前没有互相交换过的’B’交换 将a字符串的’B’与其之前没有互相交换过的’A’交换 无论如何变换a字符串都无法改变合成后的字符 无论如何变换a字符串都无法改变合成后的字符

我们发现,只有情况1和情况2才有可能改变合成后的字符。

那么可以先同时遍历字符串a和b,如果满足a[i]=='A'&&b[i]=='B'||a[i]=='B'&&b[i]=='B',则用vis数组标记,
同时统计字符串a中的A字符个数(记为suma)和B字符个数(记为sumb)。

为了避免重复计数,再遍历一次字符串a和b,
用visa记录遍历到i位置之前字符串a中有多少个已经被标记了的A字符,若出现情况①,则需要将a字符串的"A"与其之前没有互相交换过的"B"交换,共sumb-visb种交换方法,更新答案为ans+sumb-visb,
用visb记录遍历到i位置之前字符串a中有多少个已经被标记了的B字符,若出现情况②,则需要将a字符串的"B"与其之前没有互相交换过的"A"交换,共suma-visa种交换方法,更新答案为ans+suma-visa。

想清楚这些,AC就很简单了,以下代码16ms稳过。

#include 
using namespace std;
string a,b;
long long ans;
int n,suma,sumb,visa,visb,vis[1000010];//vis数组标记满足情况一或者情况二
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n)
    {
        cin>>a>>b;
        memset(vis,0,sizeof(vis));
        suma=sumb=0;
        for(int i=0;i<n;i++)
        {
            if(a[i]=='A'&&b[i]=='B'||a[i]=='B'&&b[i]=='B')vis[i]=1;
            if(a[i]=='A')suma++;
            if(a[i]=='B')sumb++;
        }
        visa=visb=ans=0;//visa记录[1,i]被标记的A的个数,visb记录[1,i]被标记的B的个数
        for(int i=0;i<n;i++)
        {
            if(a[i]=='A'&&vis[i])visa++;
            if(a[i]=='B'&&vis[i])visb++;
            if(a[i]=='A'&&b[i]=='B')ans=ans+sumb-visb;
            if(a[i]=='B'&&b[i]=='B')ans=ans+suma-visa;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

G题 nefu 1819 库特分糖果

这题的递归函数很不好写啊,因为递归是一个不易可视化的过程,类似于栈的先进后出,一层一层深入,然后不符合条件时又返回到上一层,返回之前注意清除标记(回溯),回到上一层又深入到另外的下一层寻找其他的可能性,如果所有节点都已经搜索过了,最终还是返回到了第一层,则说明不存在这样的分配方式,如果搜索到了最后一个人也有了糖果,那么就直接return,一层层返回直到退出第一层。
注意dfs函数中,从第一个人开始,确定他的糖果,如果第一个人到最后都不行,说明无法分配,如果是从第二个人开始的其他人不行,就退回上一个人并把那个人之前分的糖果标记去掉。

#include 
using namespace std;
int n,flag,a[20][20],vis[20],ans[20];
void dfs(int x,int y)
{
    int i;
    for(i=1;i<=n;i++)//第i列
    {
        if(a[x][i]==1&&vis[i]==0)
        {
            ans[x]=i;
            vis[i]=1;
            dfs(x+1,i);
        }
    }//退出循环时i=n+1
    if(ans[n]!=0)return;//最后一个人也有了糖果,结束
    if(i==n+1&&x==1){flag=0;return;}//第一次搜索第一行或者回溯搜索到第一行时找不到未被标记的1
    if(i==n+1&&x>1){vis[y]=0;return;}//清除标记,回溯
}
int main()
{
    while(cin>>n)
    {
        memset(ans,0,sizeof(ans));//注意初始化
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                cin>>a[i][j];
        flag=1;
        memset(vis,0,sizeof(vis));
        dfs(1,1);
        if(flag==0){printf("库特大失败!\n");continue;}
        for(int i=1;i<=n;i++)
        i==n?printf("%d\n",ans[i]):printf("%d ",ans[i]);
    }
    return 0;
}

———————————————————————————————————————————————

剩下的题基本上都是水题了…

———————————————————————————————————————————————

A题 nefu 1822 按钮

#include 
using namespace std;
int main()
{
    int x,y;
    cin>>x>>y;
    printf("%d\n",max(max(x*2-1,y*2-1),x+y));
    return 0;
}

B题 nefu 1823 看海

#include 
using namespace std;
int n,flag,ans,a[110];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        flag=0;
        for(int j=1;j<=i-1;j++)
        {
            if(a[j]>a[i])
            {flag=1;break;}
        }
        if(flag==0)ans++;
    }
    printf("%d\n",ans);
    return 0;
}

C题 nefu 1824 0-1字符串

#include 
using namespace std;
int tmp1,tmp2,ans;
int main()
{
    string a;
    cin>>a;
    for(int i=0;i<a.length();i++)
    {
        if(i%2==0&&a[i]!='0')tmp1++;
        else if(i%2!=0&&a[i]!='1')tmp1++;
        if(i%2!=0&&a[i]!='0')tmp2++;
        else if(i%2==0&&a[i]!='1')tmp2++;
    }
    ans=min(tmp1,tmp2);
    printf("%d\n",ans);
    return 0;
}

D题 nefu 1825 逃出迷宫

BFS基础题,不多说。

#include 
using namespace std;
int n,m,newx,newy,a[110][110],vis[110][110];
int dir[8][2]={{1,0},{-1,0},{0,-1},{0,1},{1,1},{1,-1},{-1,1},{-1,-1}};
struct node
{
    int x,y,cnt;
};
queue<node>q;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    q.push({1,1,0});
    int flag=0;
    while(!q.empty())
    {
        node tmp=q.front();q.pop();
        if(tmp.x==n&&tmp.y==m){printf("%d\n",tmp.cnt);flag=1;break;}
        vis[tmp.x][tmp.y]=1;
        for(int i=0;i<8;i++)
        {
            newx=tmp.x+dir[i][0]*a[tmp.x][tmp.y];
            newy=tmp.y+dir[i][1]*a[tmp.x][tmp.y];
            if(newx>=1&&newx<=n&&newy>=1&&newy<=m&&vis[newx][newy]==0)
            q.push({newx,newy,tmp.cnt+1});
        }
    }
    if(flag==0)printf("BOMB\n");
    return 0;
}

E题 nefu 1821 库特的飞船

先用素数筛的模板打表素数,之后打表pre数组,pre[i]表示[1,i]区间内的素数和。
如果不先打表pre数组记录区间内素数和就会TLE,注意在询问区间前要先打表。

#include 
using namespace std;
const int N=1e6+10;
int l,r,t,tmp,cnt,prime[N],pre[N];//pre数组记录[1,i]区间内的素数和
bool flag[N];//flag标记合数为0,素数为1
void get_prime()//素数筛,打表素数
{
    memset(flag,1,sizeof(flag));
    flag[1]=cnt=0;
    for(int i=2;i<=N;i++)
    {
        prime[++cnt]=i;
        for(int j=1;j<=cnt&&prime[j]*i<=N;j++)
        {
            flag[prime[j]*i]=0;
            if(i%prime[j]==0)break;
        }
    }
}
void get_pre()//打表pre数组
{
    for(int i=1;i<=N;i++)
    {
        if(flag[i])tmp=tmp+i%2;
        pre[i]=tmp;
    }
}
int main()
{
    get_prime();get_pre();
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>l>>r;
        printf("%d\n",pre[r]-pre[l-1]);
    }
    return 0;
}

F题 nefu 1820 库特大危机

这题注意分类讨论。

#include 
using namespace std;
int t,x,y,z,tmp,ans;
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>x>>y>>z;
        if(x>=z) {printf("1\n");continue;}
        if(x<=y&&x<z){printf("库特大危机!\n");continue;}
        if(x>y&&x<z)
        {
            tmp=z-x;
            if(tmp%(x-y)==0)ans=tmp/(x-y)+1;
            else ans=tmp/(x-y)+2;
            printf("%d\n",ans);
        }
    }
    return 0;
}

你可能感兴趣的:(ACM-网络赛/校赛)