数论 (由用使用markdown写的代码无法缩进篇幅较长...)
A - 质数筛 LightOJ - 1370
思路 : 运用了欧拉函数的一个性质 :当n为质数是 f(n)=n-1
问题 给出 一个分数要求 竹子长度的欧拉函数大于等于分数
由上述定理可知长度一定大于分数 只需要找到分数+1往上的一个素数
减去1就是满足要求的最最短长度的最大的分数 !
代码如下
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int prime[1000025],pri[1000025],ans=0;
int main()
{
int n,t;
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<=1000020;i++)
{
if(prime[i])
pri[ans++]=i;
for(int j=0;j<ans&&i*pri[j]<=1000020;j++)
{
prime[i*pri[j]]=0;
if(!i%pri[j])
break;
}
}
cin>>t;
for(int k=1;k<=t;k++)
{
cin>>n;
long long sum=0;
for(int i=0;i<n;i++)
{
int a;
cin>>a;
for(int j=a+1;;j++)
{
if(prime[j])
{
sum+=j;
break;
}
}
}
printf("Case %d: %lld Xukha
",k,sum);
}
return 0;
}
B - 分解质因数 LightOJ - 1341
思路: 欧拉筛素数 唯一分解定理 暴力 根下1012=106
唯一分解定理 p=p1a1*p2a2....pn^an;
则 P的因子个数为 sum=(1+a2)(1+a2)*(1+an);
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 1000010
using namespace std;
bool flag[maxn];
int pri[maxn],sum,t,ans=0;
long long a,b;
int main()
{
memset(flag,1,sizeof(flag));
for(int i=2;i<=maxn;i++)
{
if(flag[i])
pri[ans++]=i;
for(int j=0;j<ans&&pri[j]*i<=maxn;j++)
{
flag[pri[j]*i]=0;
if(!i%pri[j])
break;
}
}
cin>>t;
for(int tt=1;tt<=t;tt++)
{
cin>>a>>b;
if(a<b*b)
printf("Case %d: 0
",tt);
else
{
int cnt=0;
sum=1;
for(int i=1;i<b;i++)
if(!(a%i))
cnt++;
for(int i=0;i<ans&&pri[i]<=sqrt(a);i++)
{
int ant=0;
while(!(a%pri[i]))
{
ant++;
a/=pri[i];
}
sum*=ant+1;
}
if(a>1)
sum*=2;
sum/=2;
printf("Case %d: %d
",tt,sum-cnt);
}
}
return 0;
}
D - Leading and Trailing LightOJ - 1282
思路:大数转化 快速幂 模拟快速幂
正常 为 取余所mod数
前置保留利用 double型数据 进行前几位保操作
当 乘积大于等于1000 数字/10;最终转换为int输出就是
前三位 PS:后三位存在前导零
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
int t;
LL num;
int k,l;
double f;
cin>>t;
for(int tt=1;tt<=t;tt++)
{
cin>>num>>k;
LL numm=num;
l=1;
int m=k;
while(k)
{
if(k%2)
{
l%=1000;
l*=numm%1000;
}
numm%=1000;
numm*=numm;
k/=2;
}
l%=1000;
double nummm=num*1.0;
f=1.0;
while(m)
{
if(m%2)
{
while(f>=1000.0)
f/=10.0;
f*=nummm;
}
while(nummm>=1000.0)
nummm/=10.0;
nummm*=nummm;
m/=2;
}
while(f>=1000.0)
f/=10.0;
int ff=f;
printf("Case %d: %d %03d
",tt,ff,l);
}
}
E - Goldbach`s Conjecture LightOJ - 1259
思路:欧拉筛素数+暴力
利用欧拉筛特性 生成的标记数组 以及 素数数组进行
素数 与 数字减去素数 判定 效率提升
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e7+10;
int pri[5000000];
bool map[maxn];
int main()
{
memset(map,1,sizeof(map));
int ans=0;
map[1]=0;
for(int i=2;i<maxn;i++)
{
if(map[i])
pri[ans++]=i;
for(int j=0;j<ans&&pri[j]*i<maxn;j++)
{
map[i*pri[j]]=0;
if(!(i%pri[j]))
break;
}
}
int n;
cin>>n;
for(int time=1;time<=n;time++)
{
int num,cnt=0;
cin>>num;
for(int i=0;i<ans&&pri[i]<=num/2;i++)
{
if(map[num-pri[i]])
cnt++;
}
printf("Case %d: %d
",time,cnt);
}
return 0;
}
F - Harmonic Number (II) LightOJ - 1245
思路: 验证得出 数字sqrt(n)之前可以直接计算
sqrt(n)之后可以通过 区间计算缩短运算时间 进而防止TLE出现
诸如 3=n/3---n/4之间的数据
区间和为 3*(n/4-n/3)
代码如下:
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
int main()
{
int T;
LL n;
cin>>T;
for(int cas=1; cas<=T; cas++)
{
cin>>n;
int m = sqrt(n);
LL ret = 0;
for(int i=1; i<=m; i++)
ret += n/i;
for(int i=1; i<=m; i++)
ret += (n/i - n/(i+1))*i;
if(m == n/m)
ret -= m;
cout<<"Case "<<cas<<": "<<ret<<endl;
}
return 0;
}
H - Harmonic Number LightOJ - 1234
思路:有2.
1 ). 10000之前进行直接计算,10000之后利用欧拉常数直接求值
2 ).10^8数据每40个数据存一次实际 运算 sum一直在++但始终没有明白
所谓的1000ms究竟限制的是哪一部分 10^8的运算 但却没有超3S限制
(这个思路很新奇 )
欧拉常数:r=0.57721566490153286060651209;
a=log(n)+r+1.0/(2*n);
代码1:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const double r=0.57721566490153286060651209;
double a[10008];
int main()
{
a[1]=1;
for(int i=2;i<10007;i++)
{
a[i]=a[i-1]+1.0/i;
}
int t;
cin>>t;
for(int tt=1;tt<=t;tt++)
{
long long n;
cin>>n;
if(n<10000)
printf("Case %d: %.10lf
",tt,a[n]);
else
printf("Case %d: %.10lf
",tt,log(n)+r+(1.0/(2.0*n)));
}
return 0;
}
代码二:
#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 1e8+10
#define mine 2500005
using namespace std;
double num[mine];
int main()
{
int t;
long long n;
double sum=1;
num[1]=1;
for(long long i=2;i<=maxn;i++)
{
sum+=(1.0/i);
if(!(i%40))
num[i/40]=sum;
}
cin>>t;
for(int time=1;time<=t;time++)
{
cin>>n;
long long x=n/40;
sum=num[x];
for(long long ll=n;ll>40*x;ll--)
sum+=(1.0/ll);
printf("Case %d: %.10lf
",time,sum);
}
return 0;
}
I - Mysterious Bacteria LightOJ - 1220
思路: 唯一分解定理 + gcd()
利用唯一分解定理将数字分解成 若干 数字幂相乘形式
利用gcd 求出他们最大公约数 来判断最小幂数
(例子:22*34-gcd(2,4)=2--(232)2=18^2
22*33-gcd(2,3)=1--427^1)
另外要注意 负数形式
只有当 幂次为奇数是才为负数 因此要将求得gcd不断判断偶则/2
直至为奇数 才为最终答案 !~
代码如下:
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int maxn = 1e5+10;
bool vis[maxn] = {0};
int prime[maxn];
int ret;
void IsPrime()
{
ret = 0;
vis[1] = 1;
for(int i = 2 ; i <= maxn ; i++)
{
if(vis[i] == 0)
{
prime[ret++] = i;
for(int j = 2 ; j * i < maxn ; j++)
{
vis[i*j] = 1;
}
}
}
}
signed main()
{
int t , ans;
ll n;
IsPrime();
cin >> t;
for(int k = 1 ; k <= t ; k++)
{
cin >> n;
int sum = 0 ;
int flag = 0;
if(n < 0)
{
n = -n;
flag = 1;
}
for(int i = 0 ; i < ret ; i++)
{
if(n % prime[i] == 0)
{
ans = 0;
while(n % prime[i] == 0)
{
ans++;
n /= prime[i];
}
if(sum == 0)
{
sum = ans;
}
else
{
sum = __gcd(sum , ans);
}
}
}
if(n > 1)
{
sum = 1;
}
if(flag == 1)
{
while(sum % 2 == 0)
{
sum = sum/2;
}
}
printf("Case %lld: %lld
" , k , sum);
}
return 0;
}
J - Large Division LightOJ - 1214
思路:大数模拟 暴力? 取余定理 a=c+d-a%b=(c%b+d%b)%b;
核心 大数模拟 numnow=numago*10+(string)b[now]-48; numnow%=b;
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<sstream>
using namespace std;
int main()
{
int n;
cin>>n;
for(int t=1;t<=n;t++)
{
string a;
char as[1000];
long long b,x=0;
cin>>a>>b;
if(a.length()==1&&a[0]=='0')
printf("Case %d: divisible
",t);
else
{
abs(b);
if(a[0]=='-')
a.erase(0,1);
for(int i=0;i<a.length();i++)
{
x=(x*10+a[i]-'0')%b;
}
x%=b;
if(!x)
printf("Case %d: divisible
",t);
else
printf("Case %d: not divisible
",t);
}
}
return 0;
}
M - Trailing Zeroes (III) LightOJ - 1138
思路: 推理得知 0的个数只与 数字/5之和 相互映射
例子 5! ---120 5/5=1;
10!---10/5=2+2/5=2;
避免超时采用二分思路
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
typedef long long LL;
LL sum(LL n )
{
LL ans=0;
while(n)
{
ans+=n/5;
n/=5;
}
return ans;
}
int main()
{
int t;
cin>>t;
int cnt=1;
while(t--)
{
LL mid,q,left=1,right=1000000000,ans=0;
cin>>q;
while(right>=left)
{
mid=(left+right)/2;
if(sum(mid)<q)
left=mid+1;
else
right=mid-1;
}
int x=sum(left);
if(x==q)
printf("Case %d: %d
",cnt++,left);
else
printf("Case %d: impossible
",cnt++);
}
return 0;
}
T - Primes HDU - 2161
思路:这题真水 就是题干 定义2不是素数
直接 欧拉筛1e6数据水过
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
typedef long long LL;
int pri[maxn];
bool p[maxn];
int main()
{
int ans=0;
memset(p,1,sizeof(p));
for(int i=2;i<=maxn;i++)
{
if(p[i])
pri[ans++]=i;
for(int j=0;j<ans&&pri[j]*i<=maxn;j++)
{
p[pri[j]*i]=0;
if(!(i%pri[j]))
break;
}
}
p[1]=p[2]=0;
int a,i=1;
while(cin>>a)
{
if(a<=0)
break;
printf("%d: ",i++);
if(p[a])
cout<<"yes";
else
cout<<"no";
cout<<endl;
}
return 0;
}
U - Maximum GCD UVA - 11827
思路 : 字符流转换 以及getlin() gcd()
stringstream与 getline()详解
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<sstream>
#include<algorithm>
using namespace std;
long long gcd(long long a,long long b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
int main()
{
long long a[105],t;
cin>>t;
getchar();
while(t--)
{
long long ans=0,maxn=-1;
string str;
getline(cin,str);
stringstream st(str);
while(st>>a[ans])
{
ans++;
}
for(int i=0;i<ans;i++)
{
for(int j=i+1;j<ans;j++)
{
long long c=a[i],d=a[j];
while(d^=c^=d^=c%=d);
maxn=max(maxn,c);
}
}
cout<<maxn<<endl;
}
return 0;
}