机试指南 cha4 数学问题
%
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
// 还是A+B : 注意是末尾K位而不是第K位
/*
pow()的返回值为double类型,有时会出现返回误差
解决方法:
double x = pow(10,k);
int t = (int)x;// 先(int)(double(pow()))
*/
int main()
{
int a,b,k;
while(scanf("%d%d%d",&a,&b,&k)!=EOF)
{
if (a == 0 && b == 0)
break;
double t = pow(10,k);
int x = (int)t;
if ((a-b)%x == 0 )
cout << -1 << endl;
else
cout << a+b <<endl;
}
return 0;
}
守形数
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
// 守形数
/*
注意N的取值范围为2-100,故只能为低1位或者低2位
*/
int main()
{
int n ;
while (cin >> n)
{
int i;
if (n>=2 && n< 10)
i = 10;
else
i = 100;
int m = n*n; //尽量不用pow()
if ((m-n)%i == 0)
cout << "Yes!"<<endl;
else
cout << "No!" << endl;
}
return 0;
}
数位拆解
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
/*
*/
int main()
{
long x1,x2; // 两个小于10^9的整数,保险起见用long
int a[15],b[15];//存放两个数的每一位数字
int sum;
int i,j;
while (cin >> x1 >>x2)
{
sum = 0;
i = 0; j = 0 ;
while (x1 > 0)
{
a[i++] = x1%10;
x1/= 10;
}
while (x2 > 0)
{
b[j++] = x2%10;
x2/= 10;
}
for (int i1=0;i1<i;i1++)
for (int j1 = 0;j1<j;j1++)
sum+= a[i1]*b[j1];
cout <<sum << endl;
}
return 0;
}
进制转换
又一版A+B
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
/*
*/
int main()
{
int m,a,b;
while (cin>>m>>a>>b)
{
if (m == 0)
break;
int c = a+b;
int size = 0;int d[10];
while (c>0)
{
d[size++] = c%m;
c = c/m;
}
for (int i = size-1;i>=0;i--)
cout << d[i];
}
return 0;
}
数制转换
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/*
*/
int main()
{
int a,b,a1;
char m[20],n[20];
while (scanf("%d %s %d",&a,&m,&b)!=EOF)
{
int length = strlen(m);
int m1 = 0;
a1 = 1; // 各位初始化权重为1
for (int i = length-1;i>=0;i--)
{
int x;
if (m[i] >= '0' && m[i] <= '9')
x = m[i] - '0';
else if (m[i] >= 'a' && m[i] <= 'z')
x = m[i] - 'a' + 10;
else if (m[i] >= 'A' && m[i] <= 'Z')
x = m[i] - 'A' + 10;
m1 += x*a1;
a1 *= a;
}
int size = 0;
while (m1>0)
{
int x = m1%b;
n[size++] = (x<10)?x+'0' : x-10+'A';
m1 /= b;
}
for (int i =size-1;i>=0;i--)
cout << n[i];
cout <<endl;
}
return 0;
}
gcd lcd
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/*
*/
int gcd(int a,int b)
{
if (b == 0)
return a;
else
return gcd(b,a%b);
}
int main()
{
int a,b;
while (cin >> a >> b)
{
cout << gcd(a,b) << endl;
}
return 0;
}
// 最小公倍数:a*b / gcd(a,b)
素数筛法
素数判定
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
int judge(int n)
{
if (n ==1)
return 0;
if (n == 2)
return 1;
for (int i = 2; i <= sqrt(n)+1;i++)
{
if (n%i == 0) // i为N的一个除1和自身以外的公因数,则不是素数
return 0;
}
return 1;
}
int main()
{
int n ;
while (cin >> n)
{
if (judge(n))
cout << "yes" <<endl;
else
cout << "no" << endl;
}
return 0;
}
素数
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
// 把2-n之间所有的素数找到,在main中判断是否个位为1
int prime[10000]; // 存放找到的素数
bool isprime[10000];// 判断是否是素数
int primesize = 0;
void judge(int n)
{
for (int i = 1;i<=n;i++)
isprime[i] = false ; // 未判断
for (int i =2;i<n;i++)
{
// 从2开始,因为2本身就是素数
if (isprime[i] == true ) // 被标记成非素数
continue;
prime[primesize++] = i; // 为false时加入到prime素数数组
// 把素数的因数都标记为true
for (int j = i*i ; j<=n;j = j+i) // 为什么从i*i开始
isprime[j] = true;
}
}
int main()
{
int n ;
bool output = false;
while (cin >> n)
{
judge(n);
for (int i = 0;i<primesize;i++)
{
if (prime[i]%10 == 1)
{
if (output == false)
{
output = true;
cout << prime[i];
}
else
cout <<" "<< prime[i];
}
}
cout <<endl;
}
return 0;
}
Prime Number // 求1-10000内第K个素数
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
// 把2-n之间所有的素数找到,在main中判断是否个位为1
int prime[100001]; // 存放找到的素数
int isprime[100001];// 判断是否是素数
int primesize = 0;
void judge(int n)
{
for (int i = 1;i<=n;i++)
isprime[i] = false ; // 未判断
for (int i =2;i<n;i++)
{
// 从2开始,因为2本身就是素数
if (isprime[i] == true ) // 被标记成非素数
continue;
prime[primesize++] = i; // 为false时加入到prime素数数组
// 把素数的因数都标记为true
for (int j = i*i ; j<=n;j = j+i) // 为什么从i*i开始
isprime[j] = true;
}
}
int main()
{
int k ;
judge(100000);
while (cin >> k)
{
cout << prime[k-1] << endl;
}
return 0;
}
####分解素因数
考虑N的取值范围是109,但是如果设成109的数组则内存空间不足,所以仅测试1-100000内的素数是否为N的素因数,如果N很大,还有一个大于100000的素因数则加一即可,因为大于100000的素因数最多只能有一个,两个就炸了INT了。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
int prime[100001] ;
bool isprime[100001];
int primesize = 0;
void judge(int n)
{
for (int i =0;i<=n;i++)
isprime[i] = false;
for (int i = 2;i<n;i++)
{
if (isprime[i] == true)
continue;
prime[primesize++] = i;
for (int j = i*i;j<n;j=j+i)
isprime[j] = true;
}
}
int main()
{
int n ;
int e[100]={0},p[100]; //存放N的质因数以及指数
int k = 0;
while (cin >> n)
{
judge(100000);
int number = 0 ;
for (int i = 0;i<primesize;i++)
{
if (n%prime[i] == 0)
p[k] = i;
else
continue;
while (n%prime[i] == 0)
{
e[k] ++;
n = n/prime[i];
}
k++;
}
for (int i =0;i<k;i++)
number += e[i];
if (n!=1) // N的取值范围是10^9,若测试完100000内的素数仍不能被除尽,则说明有一个大于100000的素数
number ++;
cout << number << endl;
}
return 0;
}
整除问题(超难数学题)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
int prime[1010] ;
bool isprime[1010];
int primesize = 0;
// 为什么是1000以内的素数?因为a的取值范围是1-1000,故a没有超过1000的素因数
// 而N!能整除a,说明N!的素因数和a的素因数必定相同
void judge(int n)
{
for (int i =0;i<=n;i++)
isprime[i] = false;
for (int i = 2;i<n;i++)
{
if (isprime[i] == true)
continue;
prime[primesize++] = i;
for (int j = i*i;j<n;j=j+i)
isprime[j] = true;
}
}
int cnt[1010] ;// n!进行素因数分解后,对应prime[i]的素数的幂指数,可能为0
int cnt2[1010] ; //a的因子数
int main()
{
int n ,a;
int k ;
while (cin>> n >>a)
{
judge(1000);
for (int i =0;i<primesize;i++)
cnt[i] = cnt2[i] = 0; // 初始化两个计数器
for (int i=0;i<primesize;i++)
{
// 对n!分解素因数,遍历到0-1000的每一个素数,
int t = n;
while (t)
{
cnt[i]+=t/prime[i];
t = t/prime[i];
}
}
int ans = 100000000;
for (int i=0;i<primesize;i++)
{
while (a%prime[i] == 0)
{
cnt2[i]++;
a/=prime[i];
}
if (cnt2[i] == 0)
continue;//没有该素数则跳过,否则容易影响整除
if (cnt[i]/cnt2[i]<ans )
ans = cnt[i]/cnt2[i]; // 每计算出一个a的因数指数就和N!的比较一下
}
cout <<ans <<endl;
}
return 0;
}
二分求幂
人见人爱A^B
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
int main()
{
int a,b;
while (cin>>a>>b)
{
if (a==0 && b==0)
break;
int ans = 1;//最终结果变量
while (b!=0)
{
if (b%2==1)
{
ans *= a; // ans 累乘a
ans%=1000; // ans仅取后三位
}
b/=2;
a = a*a;//求下一位二进制位的权重
a %= 1000;//求a的后三位
}
cout << ans << endl;
}
return 0;
}
A sequence of numbers
10 min
#include<stdio.h>
#define ret 200907
long long cal(long long a,long long q,int k){
long long ans=a;
k--;
while( k > 0){
if(k%2==1){
ans = (ans * q) % ret;
}
k/=2;
q= (q*q)%ret;
}
return ans;
}
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
long long a,b,c,ans; // a,b,c取值范围为0-2^64,long long 为64位的
int k; // 10^9 int 足矣
scanf("%lld%lld%lld%d",&a,&b,&c,&k);
if(b-a==c-b)
ans=(a%ret+(k-1)*((b-a)%ret))%ret; // (a+b)%c = (a%c +b%c)%c ,防止(a+b)溢出问题
else{
long long q=b/a;
ans=cal(a,q,k);
}
printf("%lld\n",ans);
}
return 0;
}
高精度整数
a+b
超开心的是这道题我独立做出来了!虽然耗时很久,但自己思考比不停看别人的代码要强的多!
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/*
a + b 位数不超过1000位,大整数,不能用基本数据类型存储,必须用字符串或者数组的形式
12354484 324645
time : 20+20+20+20+20 = 1h 45 min
笔记:
1. 数组的初始化方式:
int b[10]={0};
但是如果是: int b[10] = {1} , 却只有第一个元素被初始化为1,其余仍为0
或者:
int a[size] ;
memset(a,0,sizeof(int)*size); 对某指针指向的内存进行赋值,全部赋值为0
2. 结构体的初始化方式:
X x1 = { 1,2.2, 'c' };
X x2[3] = { {1, 1.1, 'a'}, {2, 2.2, 'b'}}; 使用大括号中嵌套大括号的方式
3. 对齐输出0000
%0xd // x为输出的整数宽度
*/
struct bigInteger {
int digit[300];
int size; // 该大整数的位数
}; // 每四位数字保存到一个数组里
int cal(char s1[1010],int i,int n)
{
// s1[i] - s1[i-n+1]变为整数,循环N次
int ans = 0;
int r = 1;
for (int j=0;j<n;j++)
{
ans += (s1[i]-'0')*r;
i--;
r *= 10;
}
return ans;
}
void print(bigInteger a)
{
// 输出的要求很严格:非第一个数组则补齐四位
printf("%d",a.digit[a.size-1]);
for (int i = a.size-2;i>=0;i--)
{
printf("%04d",a.digit[i]);
}
cout << endl;
}
void init(bigInteger &a,char s[],int len)
{
int i;
if (len >= 4)
{
for (i = len-1;i>=3;i = i-4)
a.digit[a.size++] = cal(s,i,4);
// 如果字符串不正好是4的倍数,开头剩余必小于4
if (i!=-1)
{
a.digit[a.size++] = cal(s,i,i+1);
}
}
else
a.digit[a.size++] = cal(s,len-1,len);
}
int main()
{
bigInteger a={{0},0},b = {{0},0},c = {{0},0};
int i;
/* 1. 如何把很长的字符串输入到数组中
输入到两个字符数组中,从size-1开始每四位字符形成一个整数,存放到数组中,
从0开始倒着往数组中放,输出的时候从size反着输出即可
*/
char s1[1010],s2[1010];
int len1,len2;
while (scanf("%s %s",s1,s2)!=EOF)
{
// 初始化为0,这样后面的相加部分才不用分长短讨论
a={{0},0};b = {{0},0};c = {{0},0};
len1 = strlen(s1);
len2 = strlen(s2);
init(a,s1,len1);
init(b,s2,len2);
// 把两部分相加,从数组0号开始递增,大于10000,截断第五位,加到下一个数组
int add = 0,len = (a.size >= b.size) ? a.size : b.size;// 进位
for (i = 0;i<len;i++)
{
int temp = a.digit[i] + b.digit[i] + add;
add = temp/10000;
c.digit[c.size++] = temp%10000;
}
// print(a);
// print(b);
print(c);
}
return 0;
}
N的阶乘
39 min
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct bigInteger
{
int digit[1001]; // 1000 ! < 1000^1000,每四位存储一个
int size; // digit的长度
}a = {{0},0};
void print()
{
// 找到不为0的第一位
for (int i = 1 ;i<=1001;i++)
{
if (a.digit[i]!=0 && a.digit[i+1] == 0)
{
a.size = i;
break;
}
}
// i 指向最后一位
printf("%d",a.digit[a.size]);
for (int i = a.size-1; i >=1 ;i--)
printf("%04d",a.digit[i]);
cout << endl;
}
int main()
{
int n;
while (cin>>n)
{
a = {{0},0};
int c = 0;
a.digit[++a.size] = 1; // digit 从size=1 开始记录
for (int i = 2 ;i<=n;i++)
{
for (int j = 1;j<=1000;j++) // digit数组中的每个元素都要乘以乘数
{
a.digit[j] = (a.digit[j]*i + c);
int temp = a.digit[j];
c = a.digit[j]/10000;
a.digit[j] %= 10000;
// size什么时候增加?每一位可能会产生无数次向前的进位
}
}
print();
}
return 0;
}
####浮点数加法
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
/*
浮点数从小数点进行分割,一个字符串分割成整数和小数数组,
但小数是左对齐,整数是右对齐。加完小数之后的进位和整数相加
*/
struct bigInteger
{
int digit[1001];
int size;
int point;
}a,b,c;
int cal(char s[],int i,int n)
{
int sum = 0;
int c = 1;
for (int j = 0 ; j < n ;j++)
{
sum += (s[i--]-'0')*c;
c *= 10;
}
return sum;
}
void init(char s[],bigInteger &a)
{
int len = strlen(s);
// 找到小数点,记录位置并删除
int i;
for (i = 0;i<len;i++)
{
if (s[i] == '.')
{
a.point = i;
break;
}
}
for (i; i < len;i++)
{
s[i] = s[i+1];
}
for (i = len-2; i >= 3 ;i -= 4)
{
a.digit[++a.size] = cal(s,i,4);
}
if (i != -1)
{
// 不是4的倍数
a.digit[++a.size] = cal(s,i,i+1);
}
}
void print(bigInteger a)
{
int i;
printf("%d",a.digit[a.size]);
for (i = a.size-1 ; i >=1 ;i--)
{
printf("%04d",a.digit[i]);
}
cout << endl;
}
int main()
{
int len1,len2,len;
char s1[1001],s2[1001];
while (scanf("%s %s",s1,s2)!=EOF)
{
// 初始化biginteger结构体
init(s1,a);
init(s2,b);
print(a);
print(b);
}
return 0;
}
二分求幂 问题重做 20min
过程推演了一会儿,代码的编写比较简单,主要是把过程弄懂
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <vector>
using namespace std;
int main()
{
int a,b;
while (cin>>a>>b)
{
if (a == 0 && b == 0)
break;
int ans = 1; int r = 0; // b对2的余数
int t = a; // a的平方
while (b>0)
{
r = b%2;
b = b/2;
if (r == 1)
{
ans = (ans * t)%1000;
}
t = (t*t)%1000;
}
cout << ans << endl;
}
return 0;
}
Tr
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
const int ret = 9973;
void cal(int a[11][11],int b[11][11],int n,int c[][11])
{
int i,j,k;
for (i=1;i<11;i++)
for (j=1;j<11;j++)
c[i][j] = 0;
for (i = 1 ; i<=n;i++)
{
for (j=1;j<=n;j++)
{
for (k = 1 ; k <= n ;k++)
{
c[i][j] += a[i][k]*b[k][j];
}
}
}
}
void equal(int ans[][11],int tmp[][11])
{
int i,j;
for (i=1;i<11;i++)
for (j=1;j<11;j++)
{
ans[i][j] = tmp[i][j];
}
}
int main()
{
int t,i,j,n,k,z;
int a[11][11];
while (cin >> t)
{
for (z = 0;z<t;z++)
{
cin >> n >> k;
for (i = 1;i<n+1;i++)
for (j = 1;j<n+1;j++)
cin >> a[i][j];
int ans[11][11] =
{1,0,0,
0,1,0,
0,0,1
};
int tmp[11][11];
while (k>0)
{
if (k%2 == 1)
{
cal(ans,a,n,tmp);
equal(ans,tmp);
}
k = k/2;
//a = a * a;
cal(a,a,n,tmp);
equal(a,tmp);
}
int c = 0;
for (i = 1 ;i<=n;i++)
{
c += ans[i][i];
}
cout << c <<endl;
}
}
return 0 ;
}