怎么说呢,数论其实常用的就是那么几个知识点,只要能熟练的掌握,其实还是挺简单的(呵呵)。下面是几道典型的题:
Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家。现在,他正在为一个细胞实 验做准备工作:培养细胞样本。
Hanks 博士手里现在有 N 种细胞,编号从 1~N,一个第 i 种细胞经过 1 秒钟可以分裂为Si 个同种细胞(Si 为正整数)。 现在他需要选取某种细胞的一个放进培养皿,让其自由分裂,进行培养。一段时间以后,再把培养皿中的所有细胞平均分入 M 个试管,形成 M 份样本,用于实验。 Hanks 博士的试管数 M 很大,普通的计算机的基本数据类型无法存储这样大的M 值, 但万幸的是,M 总可以表示为 m1 的 m2 次方,即 M = m1^m2 ,其中 m1,m2均为基本数据类型可以存储的正整数。
注意,整个实验过程中不允许分割单个细胞,比如某个时刻若培养皿中有4个细胞, Hanks 博士可以把它们分入 2 个试管,每试管内 2 个,然后开始实验。 但如果培养皿中有 5 个细胞,博士就无法将它们均分入 2 个试管。 此时,博士就只能等待一段时间,让细胞们继 续分裂,使得其个数可以均分,或是干脆改换另一种细胞培养。
为了能让实验尽早开始,Hanks 博士在选定一种细胞开始培养后,总是在得到的细胞“刚 好可以平均分入 M个试管”时停止细胞培养并开始实验。现在博士希望知道,选择哪种细 胞培养,可以使得实验的开始时间最早。
第一行有一个正整数 N,代表细胞种数。
第二行有两个正整数 m1,m2,以一个空格隔开, m1^m2 即表示试管的总数 M。
第三行有 N 个正整数,第 i 个数 Si 表示第 i 种细胞经过 1 秒钟可以分裂成同种细胞的个 数。
共一行,为一个整数,表示从开始培养细胞到实验能够开始所经过的 最少时间(单位为秒)。 如果无论 Hanks 博士选择哪种细胞都不能满足要求,则输出整数-1。
input
输入样例1:
1
2 1
3
输入样例2:
2
24 1
30 12
output
输出样例1:
-1
输入样例2:
2
对于 50%的数据,有 m1^m2≤ 30000。 对于所有的数据,有 1 ≤ N ≤ 10000,1 ≤ m1 ≤ 30000,1 ≤ m2 ≤ 10000,1 ≤ Si ≤ 2,000,000,000。
时间限制:1s
空间限制:256MB
题目中要求细胞分裂之后被试管整除,又因为试管有m1^m2只,那么很明显,只要能被m1整除,就能被m1^m2整除,所以要先判断能不能被分列之后能不能被m1整除。
那么我们可以将m1和s[i]质因数分解,只要m1的质因数s[i]中都有,那么s[i]经过多次方之后一定能被m1整除(显然可得)。
接下来就是求分裂次数。因为m1=p1^a1*p2^a2…pn^an 所以m1^m2=p1^(a1*m2)*p2^(a2*m2)…。同理,s[i]^n=p1^(b1*n)*p2^(b2*n)…。
(s[i]^n)/(m1^m2)的条件就是b1*n,b2*n,…,bn*n都大于等于a1^m2,a2^m2,…,an^m2;
所以最小分裂次数就是他们每一个值之间相差的最大倍数。总的答案就是这些最大倍数之间取最小值。
#include
using namespace std;
int n,m1,m2,a[10050],t,num1[1000],b[1000],ans,ctt=1e9;
bool f[30050];
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}
void init(){
n=read();
m1=read();m2=read();
if(m1==1){
printf("0");
exit(0);
}
for(int i=1;i<=n;++i)a[i]=read();
}
void work(){
f[1]=1;
for(int i=2;i<=m1;++i)
if(!f[i])
for(int j=2;j<=m1/i;++j)
f[i*j]=1;
for(int i=2;i<=m1;++i)//分解m1
if(!f[i]&&m1%i==0){
b[++t]=i;
int x=m1;
while(x%i==0){
num1[t]++;
x/=i;
}
num1[t]*=m2;
}
for(int i=1;i<=n;++i){//用m1的质因数去除s[i]看是否能整除,并顺便求出有几个。
bool flag=1;
ans=-1000;
for(int j=1;j<=t;++j){
if(a[i]%b[j]!=0){//s[i]中没有这个质因数
flag=0;
break;
}
int x=a[i],num=0,timee;
while(x%b[j]==0){
num++;
x/=b[j];
}
if(num1[j]%num==0)timee=num1[j]/num;//算质因数指数之间相差的倍数,向上取整。
else timee=num1[j]/num+1;
ans=max(ans,timee);
}
if(!flag)continue;
ctt=min(ctt,ans);
}
if(ctt==1e9)printf("-1");
else
printf("%d",ctt);
}
int main(){
init();
work();
return 0;
}
给定n(2≤n≤10^9)值,要求x、y均为正整数,且x
一个整数n。
一个整数,表示相应的方法数是多少。
input
6
output
4
时间限制:1s
空间限制:256MB
这道题挺简单的,但是一个数轮中常见的公式变幻的类型:
因为 1/x+1/y=1/n;
所以 (x+y)/xy=1/n;
所以 n(x+y)=xy;
移相得 xy-n(x+y)=0;
两边加上n^2得 n^2-n(x+y)+n^2=n^2;
根据十字相乘法 (n-x)(x-y)=n^2;
于是这道题就转换成了求n^2的约数;
因为n=p1^a1*p2^a2*…*pn^an;
所以n^2=p1^(2a1)*p2^(2a2)..pn^(2an);
所以n^2的约数个数为(2a1+1)*(2a2+1)…(2an+1);
最后因为x
#include
using namespace std;
const int MAXN=1e5;
int n,num[MAXN],t,ans=1;
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}
void init(){
n=read();
}
void work(){
for(int i=2;i*i<=n;++i){
if(n%i==0)t++;
while(n%i==0){
num[t]++;
n/=i;
}
}
if(n>1)num[++t]=1;
for(int i=1;i<=t;++i)ans*=(2*num[i]+1);
ans/=2;
printf("%d",ans);
}
int main(){
init();
work();
return 0;
}
Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现 在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数。现 在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:
已知正整数 a0,a1,b0,b1,设某未知正整 数 x 满足:
1. x 和 a0 的最大公约数是 a1;
2. x 和 b0 的最小公倍数是 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x 的个数。请你帮 助他编程求解这个问题。
第一行为一个正整数 n,表示有 n 组输入数据。接下来的 n 行每 行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入 数据保证 a0 能被 a1 整除,b1 能被 b0 整除。
输出文件 son.out 共 n 行。每组输入数据的输出结果占一行,为一个整数。 对于每组数据:若不存在这样的 x,请输出 0;
若存在这样的 x,请输出满足条件的 x 的个数;
input
2
41 1 96 288
95 1 37 1776
output
6
2
对于 50%的数据,保证有 1≤a0,a1,b0,b1≤10000且n≤1001≤a0,a1,b0,b1≤10000且n≤100。 对于 100%的数据,保证有 1≤a0,a1,b0,b1≤2,000,000,000且n≤20001≤a0,a1,b0,b1≤2,000,000,000且n≤2000。
这道题其实就是考了gcd的性质:
1、gcd(x,a0)=a1;
gcd(x/a1,a0/a1)=1;
2、x*b0/gcd(x,b0)=b1;
gcd(x,b0)=x*b0/b1;
gcd(b1/b0,b1/x)=1;
#include
using namespace std;
int n,a0,a1,b0,b1,x,ans;
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
void work(){
ans=0;
for(int i=1;i*i<=b1;++i)
if(b1%i==0){
if(i%a1==0&&gcd(i/a1,a0/a1)==1&&gcd(b1/b0,b1/i)==1)ans++;
int j=b1/i;
if(i!=j&&j%a1==0&&gcd(j/a1,a0/a1)==1&&gcd(b1/b0,b1/j)==1)ans++;
}
printf("%d\n",ans);
}
void init(){
n=read();
for(int i=1;i<=n;++i){
a0=read();a1=read();b0=read();b1=read();
work();
}
}
int main(){
init();
return 0;
}
再也不想做数论了