第二次练习总结
第二次练习总结
- 对新手来说 这个题确实有些难了
AC代码(别照抄)
A Yes OK
- 位与 移位 提取整数的指定位
#include <stdio.h>
int main(void){
int T,n,k;
scanf("%d",&T);
while(T--){
scanf("%d%d",&k,&n);
puts(k & (1 << n)?"Yes!":"NO!");
}
return 0;
}
B 循环移位
- 注意数据范围 移出去了要有地方能接住
- 可以用数组模拟(但是不推荐)
- 可以循环(参考下面某同学的代码)
#include<stdio.h>
int main(){
int N,k,i;
unsigned long long a,a1;
while((scanf("%d%d%llu",&N,&k,&a)) != EOF){
k %= N;
for(i = 0;i < k;i++){
a1 = a;
a1 &= 1ll << (N - 1);
a <<= 1ll;
if(a1 != 0){
a |= 1;
}
a &= (1ll << N) - 1;
}
printf("%llu\n",a);
}
return 0;
}
- 也可以一行代码秒了这个题(存好模板 循环左移同理 各位可以想下)
#include <stdio.h>
#define CROL(X,i,n) ((((X)<<(i))|((X)>>((n)-(i))))&((1ull<<(n))-1ull))
//可以写上面的宏
//或者下面的函数
long long crol_ull(long long a,long long n,long long k){//对n位的二进制数a循环移位k次
return ((a << k | (a >> (n - k))) & ((1ll << n) - 1ll));
}
int main(){
unsigned long long n,k,a;
while(~scanf("%llu%llu%llu",&n,&k,&a)){
k = k % n;
printf("%llu\n",CROL(a,k,n));
}
return 0;
}
C 复数计算器
- 复数计算是重点
- 分类讨论得全面
- 格式化输出(用不好就得多分类讨论+
if-else
)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double eps = 1e-8;
int eq(double x,double y){
return fabs(x - y) < eps;
}
int isint(double x){
return fabs(round(x) - x) < eps;
}
int main(int argc,char **argv){
double a,b,c,d,x = .0,y = .0;
char op;
while(~scanf("(%lf%lfi)%c(%lf%lfi)\n",&a,&b,&op,&c,&d)){
switch(op){
case '+':
x = a + c;y = b + d;break;
case '-':
x = a - c;y = b - d;break;
case '*':
x = a * c - b * d;y = b * c + a * d;break;
case '/':
x = (a * c + b * d) / (c * c + d * d);
y = (b * c - a * d) / (c * c + d * d);
break;
}
//out:x+iy
if(eq(x,0.0)){//real==0
if(eq(y,0.0)){//real==0;imag==0
puts("0");
}
else if(eq(y,1.0)){
puts("i");
}
else if(eq(y,-1.0)){
puts("-i");
}
else if(isint(y)){
printf("%.0fi\n",y);
}
else{
printf("%.2fi\n",y);
}
}
else{//先real再imag
if(isint(x)){
printf("%.0f",x);
}
else{
printf("%.2f",x);
}
if(!eq(y,0.0)){
if(eq(y,1.0)){
printf("+i");
}
else if(eq(y,-1.0)){
printf("-i");
}
else if(isint(y)){
printf("%+.0fi",y);
}
else{
printf("%+.2fi",y);
}
}
putchar('\n');
}
}
return 0;
}
D 进制回文数
cbj
进制转换的升级版 思路类似- 读进来的是10进制就很舒服(可以思考下如果不是10进制输入该怎么办)
#include <stdio.h>
int main(){
int radix,num,i = 0,m,n,flag = 1;
char buffer[200] = {0};
char keys[40] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
scanf("%d",&radix);
while(~scanf("%d",&num)){
i = 0;flag = 1;
while(num){
buffer[i] = keys[(num % radix)];
i++;
num /= radix;
}
n = i - 1;
for(m = 0;m <= n;m++,n--){//验证回文数
if(buffer[m] != buffer[n]){
flag = 0;break;
}
}
if(flag){//反着输出
while(i--){
putchar(buffer[i]);
}
putchar('\n');
}
}
return 0;
}
E 木木枭学高中集合论
-
枚举,代码填空
-
HINT:如果算法用到了容斥原理,它们的代码主体结构差不多都长成这个样子:
外层循环跑数,内层循环跑位,然后再加一个右移取位的判断。
-
注意运算符的优先级 如果不确定可以套一堆括号
#include<stdio.h>
int main(){
int i,n;
scanf("%d",&n);
for(i = 0;i < (1 << n);i++){
int j;
for(j = 0;j < n;j++){
if(((i >> j) & 1) == 1)
printf("%d",j);
else{
printf("-");
}
}
printf("\n");
}
return 0;
}
F 高低位
GCC
编译器有__int128_t
类型 可以秒了这个题 但是需要自行解决输出输出问题- 如果你的电脑上有
linux
或者win10
和最新的gcc for windows
那么 赶 紧 存 模 板
#include <stdio.h>
void write128(__int128_t a){
if(a < 0){
putchar('-');a = -a;
}
if(a > 9)write128(a / 10);
putchar(a % 10 + '0');
}
__int128_t read128(){
__int128_t k = 0,sgn = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-')sgn = -1;
ch = getchar();
}
while(isdigit(ch)){
k = (k << 1) + (k << 3) + (ch - '0');
ch = getchar();
}
return k * sgn;
}
int main(){
__int128_t a,b,c,d,sum;
a = read128();b = read128();c = read128();d = read128();
a = (a << 64) | b;c = (c << 64) | d;
sum = a + c;
if(sum != ((__int128_t)0x8000000000000000 << 64)){
write128(sum);
}
else{
puts("-170141183460469231731687303715884105728");
}
return 0;
}
- 数组模拟也行 就是有亿点费劲
#include<stdio.h>
int main(){
unsigned long long num1w,num1s,num2w,num2s;
int a[128]={0},b[128]={0},c[128]={0};
int i=0;
int d[128]={0},x[128]={0};
int k=0,t=0;
int sum=1;
scanf("%llu%llu",&num1w,&num1s);
scanf("%llu%llu",&num2w,&num2s);
while(num1s>0){
a[i]=num1s%2;
num1s=num1s/2;
i++;
}
i=0;
while(num2s>0){
b[i]=num2s%2;
num2s=num2s/2;
i++;
}
i=64;
while(num1w>0){
a[i]=num1w%2;
num1w=num1w/2;
i++;
}
i=64;
while(num2w>0){
b[i]=num2w%2;
num2w=num2w/2;
i++;
}
for(i=0;i<127;i++){
c[i]=c[i]+a[i]+b[i];
if(c[i]>=2){
c[i]=c[i]-2;
c[i+1]=1;
}
}
c[127]=c[127]+a[127]+b[127];
if(c[127]==3||c[127]==1){
c[127]=1;
for(i=0;i<128;i++){
if(c[i]==1){
c[i]=0;
}else{
c[i]=1;
}
}
c[0]=c[0]+1;
for(i=0;i<128;i++){
if(c[i]==2){
c[i]=0;
c[i+1]+=1;
}
}
printf("-");
while(sum>0){
i=127;
for(i;i>=0;i--){
while(t<10){
t=(t<<1)+c[i];
i--;
if(i==-1){
break;
}
}
if(i==-1){
if(t<10){
break;
}
}
i++;
d[i]=1;
t=t-10;
}
x[k]=t;
t=0;
k++;
sum=0;
for(i=0;i<128;i++){
c[i]=d[i];
sum+=c[i];
}
for(i=0;i<128;i++){
d[i]=0;
}
}
for(k=k-1;k>=0;k--){
printf("%d",x[k]);
}
}else{
c[127]=0;
}
while(sum>0){
i=127;
for(i;i>=0;i--){
while(t<10){
t=(t<<1)+c[i];
i--;
if(i==-1){
break;
}
}
if(i==-1){
if(t<10){
break;
}
}
i++;
d[i]=1;
t=t-10;
}
x[k]=t;
t=0;
k++;
sum=0;
for(i=0;i<128;i++){
c[i]=d[i];
sum+=c[i];
}
for(i=0;i<128;i++){
d[i]=0;
}
}
for(k=k-1;k>=0;k--){
printf("%d",x[k]);
}
return 0;
}
G CRC16
- 读取
hexadecimal
需要在scanf
里面使用%x
格式控制符 输出也要注意类似问题
#include <stdio.h>
#include <stdlib.h>
int main(){
int a,CRC = 0xFFFF,c,d,i,flag;
while(scanf("%X",&a) != EOF){
CRC = (CRC & (0xff00)) | (((CRC & 0xff) ^ a) & 0xff);
for(i = 1;i <= 8;i++){
flag = CRC & 1;
CRC >>= 1;
if(flag){
CRC = CRC ^ 0xA001;
}
}
}
printf("%02X %02X\n",(CRC & 0xff),((CRC & 0xff00) >> 8));
return 0;
}
H 传接球
- 输出
N0t 1n my team!
别打错了
#include <stdio.h>
int main(int argc,char **argv){
int n,a,b,f;
int team[101] = {0},chuan[101] = {0},jie[101] = {0};
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);
if(team[a] == 0){
team[a] = 1;
}
if(team[b] == 0){
team[b] = 1;
}
chuan[a]++;
jie[b]++;
}
scanf("%d",&f);
if(team[f]){
printf("%d %d\n",chuan[f],jie[f]);
}
else{
puts("N0t 1n my team!");
}
return 0;
}
I 浮点数(1)
- 照着题意模拟 在纸上比划比划 定好位置会舒服些
- 位运算可以做
char s[20] = {0};
int k,E,F,bias,i;
double f,sgn;
scanf("%s",s);
while(~scanf("%d",&k)) {
E = 0;F = 0;
bias = (1 << (k - 1)) - 1.;
if(s[0] == '1')sgn = -1.;
else sgn = 1;
for(i = 0;i < k;i++){
if(s[k - i] == '1'){
E |= (1 << i);
}
}
for(i = 0;i < 15 - k;i++){
if(s[15 - i] == '1'){
F |= (1 << i);
}
}
f = 1.0 + ((double)F / (double)(1 << (15 - k)));
printf("%.8f\n",f * pow(2.0,E-bias) * sgn);//这里如果用long long转double会出事 必须用pow
}
J 浮点数(2)
- 思路类似上面的I题
- 分数化简 我们以前做过类似的 这里直接粘过来 改了改 包装了一个函数
#include <stdio.h>
int gcd(int a,int b){
return a % b == 0?b:gcd(b,a % b);
}
void frac(int m,int n,int sign){
//end preprocess m>0 n>0
if(m == 0){
puts("0");
return;
}
int g = gcd(m,n);
int a = m / g;
int b = n / g;
int res = a / b,mod = a % b;
if(res){
if(mod){
if(sign){
printf("-%d-%d/%d\n",res,mod,b);
}
else{
printf("%d+%d/%d\n",res,mod,b);
}
}
else{
if(sign){
putchar('-');
}
printf("%d\n",res);
}
}
else{
if(mod){
if(sign){
printf("-%d/%d\n",mod,b);
}
else{
printf("%d/%d\n",mod,b);
}
}
}
}
int main(){
char s[30] = {0};
//int m = 16,k = 5,n = 10;
int bias = 15;//(1<<(5-1))-1
while(~scanf("%s",s)){
char se[10] = {0};
char sf[20] = {0};
int sign = s[0] == '1',i,e = 0,f = 0;
strncpy(se,s + 1,5);
strncpy(sf,s + 6,10);
for(i = 0;i < 5;i++){
if(se[5 - i - 1] == '1')e |= (1 << i);
}
for(i = 0;i < 10;i++){
if(sf[10 - i - 1] == '1')f |= (1 << i);
}
if(e == 31){
if(f != 0){
puts("NaN");
continue;
}
else{
puts(sign?"-inf":"inf");
continue;
}
}
else{
int a,b;
if(e == 0){
a = f;
b = 1 << 24;
}
else{
a = f + (1 << 10);
b = 1 << 10;
if(e > bias){
a *= (1 << (e - bias));
}
else{
b *= (1 << (bias - e));
}
}
//输出约分后的a/b
frac(a,b,sign);
memset(s,0,sizeof(s));
}
}
return 0;
}