牛客小白月赛31

A.A|B

链接:https://ac.nowcoder.com/acm/contest/10746/A
来源:牛客网

题目描述

 

给定两个正整数a,x,统计满足以下条件的bbb的个数:

  1. 1≤b≤x1 \le b\le x1≤b≤x
  2. a∣b=a+ba|b=a+ba∣b=a+b

首先,我们知道两个数在二进制‘或’的操作下,a|b=a+b 只有在a和b两个数 对应的二进制位上的数不同才行,例如 10 | 01 = 11 (2+1=3)其他的是不行的。

再次,对于数的搜索枚举用搜索显然是超时的 O(x),可以加上记忆化,用数组保存到达某个已经经过状态的结果,最终的结果就是一个数位dp的题。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=32+10;
int dp[maxn],a[maxn],b[maxn];
int k,x;

int dfs(int pos,int lmt)
{
    if(pos==0) return 1;
    if(!lmt&&dp[pos]!=-1) return dp[pos];

    int upb= lmt ? a[pos]:1;
    int temp=0;
    for(int i=0;i<=upb;i++)
    {
        if(i&&b[pos]) continue;
        temp+=dfs(pos-1,lmt&&i==a[pos]);
    }
    if(!lmt) dp[pos]=temp;
    return temp;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(dp,-1,sizeof(dp));
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        cin>>k>>x;
        int pos=0;
        while(x)
        {
            a[++pos]=x%2;
            x/=2;
        }
        int j=0;
        while(k)
        {
            b[++j]=k%2;
            k/=2;
        }
        int ans=dfs(pos,1);
        cout<<ans-1<<endl;
    }
}

B.A + B

链接:https://ac.nowcoder.com/acm/contest/10746/B
来源:牛客网
 

题目描述

将数字以及加号用字符矩阵的形式进行表示,对应关系如下:

以字符形式给出一个运算式,请你计算结果,同时也请你将结果按照字符的形式输出

这个题的话。。。就挺好的

赛后补题整理的,可能是觉得很长时间没写代码了吧,还是慢慢写了写这个题,思路还算清晰吧

把每个数都给整理出来,然后再转回到那种图形表示的数,这里建议使用一个p,也就是把所有的数都打出来。

这样的话,我们第一步中把 图形表示的数取出来时候可以使用,第二步转回去也可以用一下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int maxn=500+10;
string p[11][6];
int n;
int trans(string a[])
{
    int ch=10;
    for(int i=0;i<=9;i++)
    {
        //cout<<a[i]<<endl;
        int flag=0;
        for(int j=1;j<=5;j++)
            if(!(a[j]==p[i][j])) flag=1;
        if(flag==0)
            return i;
        //cout<<i<<i<<endl;
    }
    //cout<<"11312313213213213"<<endl;
    return ch;
}
void init()
{
    p[0][1]="###";p[0][2]="#.#";p[0][3]="#.#";p[0][4]="#.#";p[0][5]="###";
    p[1][1]="..#";p[1][2]="..#";p[1][3]="..#";p[1][4]="..#";p[1][5]="..#";
    p[2][1]="###";p[2][2]="..#";p[2][3]="###";p[2][4]="#..";p[2][5]="###";
    p[3][1]="###";p[3][2]="..#";p[3][3]="###";p[3][4]="..#";p[3][5]="###";
    p[4][1]="#.#";p[4][2]="#.#";p[4][3]="###";p[4][4]="..#";p[4][5]="..#";
    p[5][1]="###";p[5][2]="#..";p[5][3]="###";p[5][4]="..#";p[5][5]="###";
    p[6][1]="###";p[6][2]="#..";p[6][3]="###";p[6][4]="#.#";p[6][5]="###";
    p[7][1]="###";p[7][2]="#.#";p[7][3]="#.#";p[7][4]="..#";p[7][5]="..#";
    p[8][1]="###";p[8][2]="#.#";p[8][3]="###";p[8][4]="#.#";p[8][5]="###";
    p[9][1]="###";p[9][2]="#.#";p[9][3]="###";p[9][4]="..#";p[9][5]="###";
}
int main()
{
    init();
    /*string ch="###";
    cout<<ch.substr(1)<<endl;*/
    int t;
    cin>>t;
    while(t--)
    {
        string str[6];
        for(int i=1;i<=5;i++)
            cin>>str[i];
        n=str[1].length();
        n=(n-3)/4;
        //cout<<"n: "<<n+1<<endl;
        string temp[6];
        int pre=0,ans=0;
        for(int i=1;i<=n+1;i++)
        {
            for(int j=1;j<=5;j++)
                temp[j]=str[j].substr(0,3);
            if(i<=n)
            {
                for(int j=1;j<=5;j++)
                {
                    str[j]=str[j].substr(4);
                    //cout<<str[j]<<endl;
                }
            }
            int num=trans(temp);

            if(num!=10) pre=pre*10+num;
            else
            {
                ans+=pre;
                pre=0;
            }
        }
        ans+=pre;
        //cout<<"ans: "<<ans<<endl;
        string anstr[6];
        while(ans)
        {
            int k=ans%10;ans/=10;
            for(int i=1;i<=5;i++)
            {
                string temp="";
                temp+=p[k][i],temp+=anstr[i];
                anstr[i]=temp;
            }
            if(ans!=0)
            {
                for(int i=1;i<=5;i++)
                {
                    string temp="";
                    temp+=".",temp+=anstr[i];
                    anstr[i]=temp;
                }
            }
        }

        for(int i=1;i<=5;i++)
            cout<<anstr[i]<<endl;
        cout<<endl;
    }
}

C.图像存储

链接:https://ac.nowcoder.com/acm/contest/10746/C
来源:牛客网
 

题目描述

数字图像是一个由“0”和“1”这两个元素组成的矩阵,除去边角上的元素,每个元素都有上下左右相邻的四个元素。再一个数字图像中,元素“0”代表空白,只有元素“1”所在的位置才有一个黑点。由此,一副黑白的图像得以显现。

为了能在更少的空间里存储更多的图像,一个可行的办法就是每种相同的黑块只保留一个,其他的地方只保留位置,这样便实现了压缩。查看时,只需将保留的黑块拓印到其它的位置,这样就实现了图像的复原。

可见,该技术的关键就是对不同的黑块进行记录。我们把由若干个相邻的“1”构成的区域定义为黑块,规定一个孤立的“1”也是一个黑块,黑块中“1”的个数为黑块的大小,通过上下左右平移可以实现重合并且等大的黑块为同一种黑块。现在你的任务是分别算出一个图像中黑块的个数和种数。

这个题目如果没有判别是不是同一类型的联通块的话,就是一个很简单的搜索计数就行的,所以按照原有的思路,我们只需要把其中的块都找出来然后想办法判别是不是同类型的就可以了

可以发现,这里指的“同种类型”并不是形状相同,比这个还要简单一些,是相对位置相同就可以了,不知道叙述是不是准确,我们可以看到样例中的

001100
001001
000011
101000
000110
000100  其中橙色的联通块和绿色的联通块不是“同类型”的,这样的话,我们就不用管他的形状了(因为如果只是形状相同的话,或许同一性状的不同旋转状态也是同种类型),

这样的话我们只需要找到一个定义标准就可以了,用同种标准规定记录的联通块,保存的时候就可以用set判断了。

我找的是最小的x和y。用set判断一下就可以了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e3+10;
int mp[maxn][maxn];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int n,m;
set<vector<pair<int ,int > > >S;
void BFS(int x,int y)
{
    queue<pair<int ,int > >q;
    vector<pair<int ,int > >v;

    q.push({x,y});
    v.push_back({x,y});
    mp[x][y]=0;
    int mix=x,miy=y;
    while(!q.empty())
    {
        pair<int ,int > u=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            int nx=u.first+dx[i];
            int ny=u.second+dy[i];
            if(nx<1||nx>n||ny<1||ny>m) continue;
            if(!mp[nx][ny]) continue;
            q.push({nx,ny});
            v.push_back({nx,ny});
            mp[nx][ny]=0;
            mix=min(mix,nx);miy=min(miy,ny);
        }
    }
    for(int i=0;i<v.size();i++)
    {
        v[i].first-=mix;
        v[i].second-=miy;
    }
    S.insert(v);
}
int main()
{
    while(cin>>n>>m&&n+m)
    {
        S.clear();
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%1d",&mp[i][j]);

        int cnt=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(mp[i][j])
            {
                    cnt++;BFS(i,j);
            }

        cout<<cnt<<" "<<S.size()<<endl;
    }
}

D.坐标计数

链接:https://ac.nowcoder.com/acm/contest/10746/D
来源:牛客网
 

题目描述

定义一个坐标变换,坐标 (x,y) 变换后变为 (x⊕y,∣x−y∣)(x \oplus y, |x-y|)(x⊕y,∣x−y∣)。

给定一片矩形区域,计算区域内有多少个整数点在经过有限次变换后变为 (0,0)。

结论是:题意里面的点都是可以的,所以直接计数就可以了 (别忘了long long

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll x1,x2,y1,y2;
        cin>>x1>>y1>>x2>>y2;
        ll ans=(x2-x1+1)*(y2-y1+1);
        cout<<ans<<endl;
    }
}

E.解方程

链接:https://ac.nowcoder.com/acm/contest/10746/E
来源:牛客网
 

题目描述

给出两个正整数 a,b,计算满足方程 a*x+b*y=x*y 的正整数(x, y) 的组数。

结论是a*b的因子个数,

看了别人的题解 

a×x+b×y=x×y;a×x+b×y+a×b=x×y+a×b;a×b=x×y−a×x−b×y+a×b;a×b=(x−a)×(y−b)真的强

F.消减整除

链接:https://ac.nowcoder.com/acm/contest/10746/F
来源:牛客网
 

题目描述

给你一个数字N依序减掉1,2,3,...直到不够减。如果刚好减到0就结束,否则就加上N继续从1开始减,直到减到0为止。

请给出一个数字,计算对于该数字一共重复了几次这个过程。

G.简单题的逆袭

题目描述 

给定x,y,找出满足方程 x^k \le yxk≤y 的最大的k

赛时是我的队友饼宝做的这个题,应该是没有遇到太大的困难吧,可能是用的python的原因

import math
 
def main():
    t = int(input())
    for _ in range(t):
        x,y=list(map(int,input().split()))
        k=0
        for i in range(80):
            if x**i>y:
                k=i
                break
        print(k-1)
main()

H.对称之美

链接:https://ac.nowcoder.com/acm/contest/10746/H
来源:牛客网
 

题目描述

给出n个字符串,从第1个字符串一直到第n个字符串每个串取一个字母来构成一个新字符串,新字符串的第i个字母只能从第i行的字符串中选出,这样就得到了一个新的长度为n的字符串,请问这个字符串是否有可能为回文字符串?

这题比较简单吧,找出中间点,向两端点靠拢,过程中看看是不是有相同元素即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100+10;
int vis[maxn]['z'-'a'+10];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(vis,0,sizeof(vis));

        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            string str;
            cin>>str;
            for(int j=0;j<str.length();j++)
                vis[i][str[j]-'a']=1;
        }

        int zhong=n/2;
        int i,j;
        if(n%2==1)
        {
            zhong++;
            i=zhong-1,j=zhong+1;
        }
        else
        {
            i=zhong,j=zhong+1;
        }
        int flag=0;
        for(;i>=1&&j<=n;i--,j++)
        {
            int flag1=0;
            for(int s='a'-'a';s<='z'-'a';s++)
                if(vis[i][s]&&vis[j][s])
                    flag1=1;
            if(flag1==0)
                flag=1;
        }
        if(flag==0)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
}

I.非对称之美

题目描述 

给出一个字符串,求最长非回文子字符串的长度

当时我的思路是从两端找不相等的地方,借此找出 两个位置,这两个位置应该是在最长非回文串中的距离中间点距离相等的对应位置,想的可能是太多了吧。

后续我的队友饼宝,发现一共就三种情况,n n-1 0 看他简简单单的过了我心态都快崩了

这题大概开赛30分钟我都没过。。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;


int main()
{
    string str;
    cin>>str;
    int n=str.length();
    int flag=0;
    for(int i=0; i<n; i++)
        if(str[i]!=str[0])
            flag=1;
    int ans;
    for(int i=0; i<=n/2; i++)
        if(str[i]!=str[n-i-1])
        {
            ans=n;
            break;
        }
        else
            ans=n-1;
    if(flag==1)
        cout<<ans<<endl;
    else
        cout<<0<<endl;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值