牛客小白月赛31——补题记

参加完比赛,AC率1/10,最大的收获是

int t;
cin>>t;
while(t--){}

那是写的相当熟练了(🤣)
下面上题目列表
在这里插入图片描述

A-A|B

位运算题目,我目前还没有提交这道题,只是刚刚看懂代码,注释还有点小疑问,在这里先把注释粘过来了,以后做的多了应该自然就能理解了吧😔

作者:LYU_舌尖上的友谊
链接:https://ac.nowcoder.com/discuss/587485?type=101&order=0&pos=17&page=1&channel=-1&source_id=1
来源:牛客网

假设 A=100100010,则满足 A+B=A|B 条件的B,在 A 中为1的位置必定为0,也就是 B=0xx0xxx0x,其中的 x 可为 0 或 1,因此只要数一下 A 裡面有几个位元是 0,算出 2 的次方就可以得到答案。

但是题目又规定 B <=X ,所以我们要将 X 分段处理,假设 X=1001000100,先找出最左边第一个出现的 1 为 1000000000,分出第一段数字 xxxxxxxxx,(不含上面的数)
也就是 0 ~ 111111111 (1000000000-1),再用这一段去找有几个位置在 A 中是 0。接下来再找出第二个出现的 1 为 1000000,而第二段数字为 1000xxxxxx,也就是 1000000000 ~ 1000111111 (1001000000-1),数字的最前面固定是 1000,一样找出后面的位置有几个在 A 中是 0。
要注意的是,如果这个位置在 X 和在 A 中同时为 1,则后面就不会再有答案。因为这个做法只能处理到 X-1,所以 X 要另外处理。
最后,因为题目要求要正整数,但这个做***包含 0,所以答案要再减一。

#include <bits/stdc++.h>
using namespace std;
int A[32];
int a, x, t;
int ans, c, bit, bit2;
int main() {
    for (int i = 0; i < 31; ++i)
        A[i] = pow(2, i);
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &a, &x);
        for (bit = (1 << 30), ans = 0; bit; bit >>= 1) {
            if ((bit & x) == 0) continue;
            for (bit2 = (bit >> 1), c = 0; bit2; bit2 >>= 1)
                if ((bit2 & a) == 0) c++;
            ans += A[c];
            if (bit & a) break;
        }
        if ((a | x) == (a + x)) ans++;
        printf("%d\n", ans - 1);
    }
    return 0;
}

D-坐标计数

这道题好可惜,本来在纸上演算已经发现了规律,但是忘记用scanf输入导致98分未能通过,追悔莫及
规律:每一组数(每一个点)经过坐标变换都可以转化为符合题意的结果,所以题目就是求那个区域内,点的个数

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long int x1,x2,y1,y2;
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        long long int d=(x2-x1+1)*(y2-y1+1);
        cout<<d<<endl;
    }
    return 0;
}

E-解方程

推导过程值得学习(我是真的想不到)

作者:LYU_舌尖上的友谊
链接:https://ac.nowcoder.com/discuss/587485?type=101&order=0&pos=17&page=1&channel=-1&source_id=1
来源:牛客网
在这里插入图片描述

题解中使用了素数筛和唯一分解定理原文链接
在这里插入图片描述在这里插入图片描述
有了这两个知识储备,理解这段代码就丝毫不成问题了

#include <bits/stdc++.h>
#define MaxN 1000000
using namespace std;
typedef long long ll;
int m[MaxN];

ll p[78500];
int ps;
void sushu()//素数筛
{memset(m,0,sizeof(m));
    int i,j,k,q=int(sqrt(MaxN));
    p[0]=2;
    for(i=3; i<q; i+=2)
    {
        if(!m[i])
            for(k=2*i,j=i*i; j<MaxN; j=j+k)
                m[j]=1;
    }
    for(ps=1,i=3; i<MaxN; i+=2)
        if(!m[i]) p[ps++]=i;
}
int main()
{
    sushu();
    ll a,b,kk;
    int t,cnt,i,ans;
    cin>>t;
    while(t--)
    {
        scanf("%lld%lld",&a,&b);
        kk=a*b;
        if(kk==1) cout<<1<<endl;
        else
        {
            ans=1;
            for(i=0; i<ps&&kk!=1; i++)
            {
                for(cnt=1; kk%p[i]==0; cnt++)
                    kk/=p[i];
                ans*=cnt;
            }
            if(kk!=1)ans*=2;
            cout<<ans<<endl;
        }
    }
    return 0;
}

F-消减整数

这也是一道数学题,直接模拟就超时了

作者:LYU_舌尖上的友谊
链接:https://ac.nowcoder.com/discuss/587485?type=101&order=0&pos=17&page=1&channel=-1&source_id=1
来源:牛客网

假设第一次不够减时,是想要减K而只剩下M。则第二次就会剩下2∗M,第三次剩下3∗M,直到剩下的数量大于等于K时减去K,减去K后剩下的又不足K,又要重头开始减。

所以题目就转化为:每次加M,大于等于K时就减掉K,问多少次以后归零。

稍加观察可以发现,归零的时候加的数值总和为K的倍数,而能够加的有只有M的倍数,所以题目是在问:最快加了多少次以后变为M,K的公倍数,就是求最小公倍数。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    for(cin>>T;T;T--)
    {
        int n;int x=1;cin>>n;
        while(n-x>=0)    n-=x,x++;
        for(int i=1;;i++)
        {
            if(i*n%x==0)
            {
                cout<<i<<'\n';break;
            }
        }
    }
    return 0;
}

G-简单题的逆袭

按照我的想法是(long long)log(y)/log(x),但是由于精度问题,这样是过不了的,所以参考了题解的代码,收获是学会了如何用整数模拟<=过程

#include <bits/stdc++.h>
using namespace std;
int main()
{
    long long int x,y;
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%lld%lld",&x,&y);
        if(y==0||x<=1) cout<<-1<<endl;
        else {
            long long ans=0;
            while(y>=x)
            {
                ans++;
                y/=x;
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}

H-对称之美

这道题就是我引以为傲的独子了哈哈,其简单程度可见一斑O(∩_∩)O直接上代码了(●ˇ∀ˇ●)

#include <bits/stdc++.h>

using namespace std;
int main()
{
    char zimu[105][55];
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        getchar();
        for(int i=0;i<n;i++)
            scanf("%s",zimu[i]);
        int i,j,p,k;
        int flag=1,ok;
        for(i=0,j=n-1; i<j; i++,j--)
        {
            for(p=0; zimu[i][p]; p++)
            {
                ok=0;
                for(k=0; zimu[j][k]; k++)
                {
                    if(zimu[j][k]==zimu[i][p])
                    {
                        ok=1;
                        break;
                    }
                }
                if(ok) break;
            }
            if(!ok)
            {
                flag=0;
                break;
            }
        }
        if(flag) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
        }
        return 0;
}

I-非对称之美

这道题真的是米奇妙妙屋啊(o゜▽゜)o☆
一共只有三种情况:
①长度为0:aaaaaaa的情况
②长度为n: 整条字符串只要不对称(严格对称),就不会回文!!
③长度为n-1:最长的回文部分(n)-1就不回文了呀!!

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+65;
char s[N];
int main()
{
    bool flag=true;int n;
    scanf("%s",s+1);n=strlen(s+1);
    for(int i=1;i<=n/2;i++)
    {
        if(s[i]!=s[n-i+1])    flag=false;
    }int len=0;
    if(flag)
    {
        bool f=true;
        for(int i=2;i<=n;i++)
            if(s[i]!=s[i-1])    f=false;
        if(f)    cout<<0<<endl;
        else    cout<<n-1<<endl;    
    }
    else        cout<<n<<endl;
    return 0;
}

本次比赛的题目就补到这里了,剩下的几道题有关搜索,贪心等算法,小白我还没有学到,学会了一定补上(●ˇ∀ˇ●)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值