数论总结

数论 (由用使用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\n",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\n",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\n",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\n",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\n",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\n",tt,a[n]);
	else
	printf("Case %d: %.10lf\n",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\n",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--4
27^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\n" , 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\n",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\n",t);
	  else
     printf("Case %d: not divisible\n",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\n",cnt++,left);
	  else
	       printf("Case %d: impossible\n",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 ;
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;
}           

posted @ 2019-06-09 10:37  MaxVen  阅读(223)  评论(0编辑  收藏  举报