位运算符
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,并且∑nak=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.类似于普通筛选法