POJ 1284:给一个数奇质数P,求P的原根个数
对正整数( a, m) = 1,如果 a 是模 m 的原根,那么 a 是 整数模n乘法群(即加法群 Z/m Z的可逆元,也就是所有与 m 互素的正整数构成的 等价类构成的乘法群) Zn的一个 生成元。由于 Zn有 φ( m)个元素,而它的生成元的个数就是它的可逆元个数,即 φ(φ( m))个,因此当模 m有原根时,它有φ(φ( m))个原根。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int euler(int n)
{
int res=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
res=res/i*(i-1);
while(n%i==0)
n/=i;
}
if(n>1)
res=res/n*(n-1);
return res;
}
int main()
{
int n;
while(cin>>n)
{
cout<<euler(n-1)<<endl;
}
return 0;
}
POJ 2773 给定一个M,求第K个与M互素的数是多少
思路:先求出不大于M,且与M互素的数,并记录有多少个(即PHI(M)个),然后对于大于M时,不难发现在KM--(K+1)M的范围中,都有PHI(M)个数与M互素(自己列表写一写),也即第K个与M互素的数对M取余具有周期性且T=PHI(M),因此当求出了不大于M的PHI(M)个与M互素的数,剩下的可以用周期性求出比M大且与M互素的数。当然这是暴力的做法,网上用容斥定理+二分可以完美解决,虽然不明觉厉。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000005;
int prime[maxn];
int gcd(int a,int b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
int main()
{
int m,k;
while(cin>>m>>k)
{
int cnt=0;
for(int i=1;i<=m;i++)
{
if(gcd(m,i)==1)
prime[cnt++]=i;
}
if(k%cnt!=0)
cout<<(k/cnt)*m+prime[k%cnt-1]<<endl;
else
cout<<(k/cnt-1)*m+prime[cnt-1]<<endl;
}
return 0;
}
POJ 2478 给定一个N,快速求PHI(1)+PHI(2)+.....PHI(N)的和。
如果用前面那种一个一个求PHI的模板,直接TLE,因此得打表生成PHI(N)的数组,打表的思路与筛法类似,记住就好。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int phi[1000005];
void euler()
{
for(int i=1;i<=1000000;i++)
phi[i]=i;
for(int i=2;i<=1000000;i+=2)
phi[i]=phi[i]/2;
for(int i=3;i<=1000000;i+=2)
{
if(phi[i]==i)
{
for(int j=i;j<=1000000;j+=i)
{
phi[j]=phi[j]/i*(i-1);
}
}
}
}
int main()
{
euler();
while(scanf("%d",&n)!=EOF)
{
if(n==0)
return 0;
long long sum=0;
for(int i=2;i<=n;i++)
{
sum+=phi[i];
}
printf("%I64d\n",sum);
}
return 0;
}
POJ 3090 求第一象限中从原点出发到各个格点组成的不同斜率的个数。
裸的法雷级数的知识:每一行从0/1开始,以1/1结尾,其它数自左至右将所有的真分数按增加顺序排列;第n行是由所有分母小于或等于n的真分数组成,我们称为n阶法雷级数。这里就是要求N阶法雷级数有多少个。
设法雷级数N阶有PHI(N)个,则不难得出PHI(N)=PHI(N-1)+phi(N):实际上就是在前一项的基础上多了分母为N,分子不大于N且与N互素的个数。
故PHI(N)=PHI(N-1)+phi(n)=PHI(N-2)+phi(N-1)+phi(N)----------->=sigema(phi(i))(i从1-n)+1。
回归这道题:第一象限不同斜率的个数:以斜率为1的射线为对称轴,射线下方符合条件的总数恰为sigema(phi(i))(i从1-n),上方亦如此,最后再加上对称轴上的一个点即为该题的解。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int phi[10005];
void euler()
{
for(int i=1;i<=1000;i++)
phi[i]=i;
for(int i=2;i<=1000;i+=2)
phi[i]/=2;
for(int i=3;i<=1000;i+=2)
{
if(phi[i]==i)
{
for(int j=i;j<=1000;j+=i)
{
phi[j]=phi[j]/i*(i-1);
}
}
}
}
int main()
{
int t;
cin>>t;
int cas=0;
euler();
while(t--)
{
int n;
cin>>n;
int sum=0;
for(int i=1;i<=n;i++)
sum+=phi[i];
cout<<++cas<<" "<<n<<" "<<2*sum+1<<endl;
}
return 0;
}
POJ 3358
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2975 | Accepted: 787 |
Description
Let {x} = 0.a1a2a3... be the binary representation of the fractional part of a rational number z. Suppose that {x} is periodic then, we can write
{x} = 0.a1a2...ar(ar+1ar+2...ar+s)w
for some integers r and s with r ≥ 0 and s > 0. Also, (ar+1ar+2...ar+s)wdenotes a nonterminating and repeating binary subsequence of {x}.
The subsequence x1 = a1a2 ... aris called the preperiod of {x} and x2 = ar+1ar+2 ... ar+s is the period of {x}.
Suppose that |x1| and |x2| are chosen as small as possible then x1 is called the least preperiod and x2 is called the least period of {x}.
For example, x = 1/10 = 0.0001100110011(00110011)w and 0001100110011 is a preperiod and 00110011 is a period of 1/10.
However, we can write 1/10 also as 1/10 = 0.0(0011)w and 0 is the least preperiod and 0011 is the least period of 1/10.
The least period of 1/10 starts at the 2nd bit to the right of the binary point and the the length of the least period is 4.
Write a program that finds the position of the first bit of the least period and the length of the least period where the preperiod is also the minimum of a positive rational number less than 1.
Input
Each line is test case. It represents a rational number p/q where p and q are integers, p ≥ 0 and q > 0.
Output
Each line corresponds to a single test case. It represents a pair where the first number is the position of the first bit of the least period and the the second number is the length of the least period of the rational number.
Sample Input
1/10 1/5 101/120 121/1472
Sample Output
Case #1: 2,4 Case #2: 1,4 Case #3: 4,4 Case #4: 7,11题意:求一个分数n/m在二进制形式表示下的最小循环节长度以及起点位置。
思路:
现在假设起始循环的第i个数为n,记作ni ;那么第j个数n,则是nj;这时循环数列出现,那么循环数列的长度为 L = j - i .
又根据小数点进制的计算原理,那么就有nj = ( ni * 2 ^ L ) % m ;————>2 ^ L % m == 1 % m ;(求t是利用这里求的)
当 m 与 2 互质时,根据欧拉定理,则有2^ phi( m ) == 1 %m ,因为2^ 0 == 1 , 所以起始点为0 ;也就是题目的1;
当二者不互质时,那么m % 2 != 0 ;
因此对等式进行化简 ,两边同时除以2的幂次(使得m与2互质,直到满足欧拉函数的条件),那么就有2^( L - t ) == 1 % ( m / ( 2 ^ t );可知,此时循环数列的起点为 t ,也就是题目的t+1;
最后我们要求的就是2^ L' = 1 % M' ;由于2^ k == 1 % m ',当k % m == 0 时取得有效值,因此,从小到大枚举phi(m')的因子,可得到最大值
这题是很好的一题,思路是别人的,今天跟世权做这题的时候已经再往这方面想了,但是当时打表暴力找的时候只是猜到了最小循环节会是phi()的一个因子,但是没有想到如何求起点,后来看了一下别人的思路,便也明白了如何来求起点。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int fac[1000005];
int phi;
int temp;
int p,q;
int euler(int n)
{
int res=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
res=res/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
res=res/n*(n-1);
return res;
}
int gcd(int a,int b)
{
if(b==0)return a;
else
return gcd(b,a%b);
}
int power(int a,int b,int mod)
{
int ans=1;
while(b)
{
if(b&1)
ans=(long long )ans*a%mod;
b>>=1;
a=(long long )a*a%mod;
}
return ans;
}
int main()
{
int cas=0;
while(scanf("%d/%d",&p,&q)!=EOF)
{
int g=gcd(p,q);
p/=g;
q/=g;
int len=0;
while(q%2==0)
{
len++;
q/=2;
}
int ans1=len+1;
int ans2;
phi=euler(q);
if(phi==1)
{
ans2=1;
}
else
{
int cnt=0;
for(int i=1;i*i<=phi;i++)
{
if(phi%i==0)
{
fac[cnt++]=i;
fac[cnt++]=phi/i;
}
}
sort(fac,fac+cnt);
for(int i=0;i<cnt;i++)
{
temp=power(2,fac[i],q);
if(temp==1)
{
ans2=fac[i];
break;
}
}
}
printf( "Case #%d: %d,%d\n" , ++cas , ans1 , ans2 ) ;
}
return 0;
}
欧拉函数是数论中很基础的东西,这方面的比较专业性的证明,我会在学弟写好他的长篇大论后将链接挂在这里,原来数学渣不会严谨的证明,只会乱猜= =|||