2023/3/21 第三场选拔赛总结

文章介绍了如何利用位运算符高效地处理IP地址,特别是在无分类地址CIDR表示法中计算网络地址。同时,展示了在寻找特定序列关系和构建回文数时位运算的重要性,包括快速读取数字的技巧和算法实现。
摘要由CSDN通过智能技术生成

位运算符

1.(0条未读通知) 代码查看 (nowcoder.com)

总结:遇到二进制,不能盲目的开始求每一位二进制数,结合位运算符可以节省大量时间

2.小红不分类

由于IP地址分类存在许多缺点,所以小红最近正在学习无分类地址CIDR。

其中无分类地址CIDRCIDR将3232位的IPIP地址表示为:a.b.c.d/x,其中/x表示前x位属于网络号(x的范围是0 ~ 31),也就是说子网掩码前xx位均为1,其余位均为0,将该IPIP地址与子网掩码按位进行与运算即可得到网络地址。也就是说,将该IPIP地址的其余32−x位全部改成00即可得到网络地址。

例如将134.76.231.17/24,将其转换为二进制表示即10000110010011001110011100010001/24,将剩余的8位全部改为0后得到10000110010011001110011100000000/24,再将其转换为10进制就可以得到网络地址134.76.231.0/24。

现在小红有n个IP地址,你能帮她计算一下对应的网络地址吗?

简便的代码:

#include <bits/stdc++.h>
#define debug std::cout << "debug " << __LINE__ << std::endl;
typedef long long LL;
inline int read() {
	int x = 0, c = getchar(), f = 1;
	while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); }
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return x * f;
}

template<typename T> void read(T &x) { x = read(); }
template<typename T, typename ...Argv> void read(T &x, Argv &...argv) { read(x); read(argv...); }
const int A[] = {0,128,192,224,240,248,252,254,255};
int main() {
	int n = read();
	for (int i = 1; i <= n; ++ i) {
		int a, b, c, d, x; read(a, b, c, d, x);
		if (x <= 8) printf("%d.%d.%d.%d/%d", a & A[x], 0, 0, 0, x);
		else if (x <= 16) printf("%d.%d.%d.%d/%d", a, b & A[x - 8], 0, 0, x);
		else if (x <= 24) printf("%d.%d.%d.%d/%d", a, b, c & A[x - 16], 0, x);
		else  printf("%d.%d.%d.%d/%d", a, b, c, d & A[x - 24], x);
        puts("");
	}
	return 0;
}

总结:1.前面的泛型设置,是为了更快的读取数字。

           2.由题意可知,因为将二进制数变为0是从后往前依次进行的(规律很重要),所以直接设置特定的二进制位数组,再结合位运算符即可。

            3.read 的原理就是读取字符串中的数字,(x<<1)是x的2倍,(x<<3)是x的8倍,加在一起就是10倍。

3.小红写数字

小红有一个含有n个正整数的序列a,现在小红想要找到一个二元组〈i,j〉,满足1≤i<j≤n,并且∑n​ak​=ai​⋅aj​+ai​+aj​。(k=1)

你能帮小红找到吗?

正确代码:

#include <bits/stdc++.h>
#define debug std::cout << "debug " << __LINE__ << std::endl;
typedef long long LL;
inline int read() {
	int x = 0, c = getchar(), f = 1;
	while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); }
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return x * f;
}

template<typename T> void read(T &x) { x = read(); }
template<typename T, typename ...Argv> void read(T &x, Argv &...argv) { read(x); read(argv...); }

const int N = 2e5 + 100;
std::map<int, int> mp;
int a[N];
int main() {
	int n = read();
	LL sum = 0, ans = 0;
	for (int i = 1; i <= n; ++ i) sum += (a[i] = read());
	for (int i = 1; i <= n; ++ i) {
		LL o = a[i] + 1, p = sum - a[i];
		if (p % o == 0) {
			if (mp.find(p / o) != mp.end()) {
				printf("%d %d\n", mp[p / o], i);
				return 0;
			}
		}
		if (mp.find(a[i]) == mp.end()) mp[a[i]] = i;
	}
	puts("-1");
	return 0;
}

总结:1.该题的关键是:找到等式左右两边的关系,不能盲目用循环

           2.使用map记录数值与顺序。

4.小红找回文

自己写的代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
    int x=0,c=getchar(),f=1;
    while(c<'0'||c>'9'){if(c=='-') f=-f;c=getchar();};
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
template <typename T>void read(T&x){x=read();}
template<typename T,typename...Argv>void read(T&x,Argv &...argv){read(x);read(argv...);}
map<long,bool> m;
int main()
{
    long n=read(),sum=0;
    for(int i=1;i<10&&i<=n;i++){m[i]=true;sum++;}
    for(long i=1;i<=n;i++)
    {
        if(m[i]==true)
        {
            string s=to_string(i),s_r;
            s_r=s;
            reverse(s_r.begin(),s_r.end());
            s+=s_r;
            int x=0;
            for(int j=0;j<s.size();j++)
            {
                char c=s[j];
                    if(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48);
            }
            if(x<=n)
            {
                m[x]=true;
                sum++;
            }
            for(char w='0';w<='9';w++)
            {
                string s1=s;
                x=0;
                s1.insert(s1.size()/2,1,w);
                for(int j=0;j<s1.size();j++)
                {
                     char c=s1[j];
                     if(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48);
                }
                
                if(x<=n)
                {
                    m[x]=true;  
                    sum++;
                }
            }
        }
    }
    cout<<sum;
}

正确代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
using PII = pair<int, int>;

int n, cnt = 9;

signed main() {
    cin >> n;
    if (n < 10) {
        cout << n << endl;
        return 0;
    }
    int szn = to_string(n).size();
    for (int i = 1;; i++) {
        string left = to_string(i), right = left; reverse(right.begin(), right.end());
        for (int i = 0; i <= 9; i++) if (stoll(left + to_string(i) + right) <= n) cnt++; else break;
        if (stoll(left + right) <= n) cnt++; else break;
    }
    cout << cnt << endl;
    return 0;
}

总结:1.关键在于把整形转字符型 to_string函数,以及字符型转长整形stoll函数。

           2.思路:每个回文数都可以有由最初的回文数得到,加上其倒置的字符串,以及0到9。

           3.类似于普通筛选法

           https://blog.csdn.net/CPOHUI/article/details/79213776

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值