简直哭了~~~羡慕讲台上数学巨强的同级大佬
进入正题 呵~数论!
大佬“在线”辅导
一些基本概念(以下维基百科或百度即可)
一些基本定理及算法(以下维基百科或百度即可)
只是初次学习嘛,两天掌握还是蛮困难的,就题说吧
A - The Euler function HDU - 2824
题目大意:求1-n的欧拉函数的和
欧拉函数的应用,只不过要找一个快速的算法进行预处理(否则每次计算单个欧拉函数会t)
核心代码(欧拉函数打表)
int phi[N];
void Euler(){
phi[1] = 1;
for(int i = 2; i < N; i ++){
if(!phi[i]){
for(int j = i; j < N; j += i){
if(!phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
}
}
B - Divisors POJ - 2992
题目大意:给出n,k,计算 Ckn C n k ,并求该组合数求因子个数
以为先求组合数再用唯一分解定理求因子个数,结果为了求组合数不超时不溢出,特地搜到了一篇超牛掰的方法求组合数(大致思路为担心数据过大所以对组合数取对数······)。
结果依然超时。百度了一下,发现竟然有这样一个神奇的公式求一个数阶乘的因子个数:ei=[N/pi^1]+ [N/pi^2]+ …… + [N/pi^n] 其中[]为取整,显然,要对素数打表预处理,然后用唯一分解定理即可:M=(e1+1)(e2+1)……*(en+1)。
代码
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e9+7;
int n,m;
ll k[83]={
0};
int prime[]={
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431};
int num(int n, int p)
{
int ans = 0;
int tmp = p;
while(p <= n)
{
ans += n/p;
p = p*tmp;
}
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
ll ans=1;
for(int i=0;i<=82;i++)
{
int a=num(n,prime[i]);
int b=num(m,prime[i]);
int c=num(n-m,prime[i]);
ans*=(a-b-c+1);
}
printf("%lld\n",ans);
}
return 0;
}
这里要注意组合数 Cmn=n!m!(n−m)! C n m = n ! m ! ( n − m ) ! 的因子数要对每一个素数单独累乘,如代码中for循环所示。
C - Longge’s problem POJ - 2480
题目大意:求1-n的gcd(i,n)的和,题目都说到这份了显然暴力求解不可取。
不过通过打表可以发现他们的最大公约数出现是有规律的
因为i = a * b
n = a * d且 gcd(b, d) = 1
所以gcd(i, n) = a ⟹ ⟹ gcd(1,n/i)=1 ⟹ ⟹ 发现每个最大公约数出现的次数为phi(n/i),使用欧拉函数即可。
问题又来了,单个分开求会T,这里给出大神的代码(还没看懂为啥原来的会T)
代码
#include
#include
#include
#include
#define LL long long
#define MOD 1000000007
using namespace std;
int main(){
LL n;
while(scanf("%lld",&n)!=EOF){
LL ans=1;
for(LL i=2;i*i<=n;i++)
if(n%i==0){
LL k=0,p=1;
while(n%i==0){
k++;
p*=i;
n/=i;
}
ans*=k*(p-p/i)+p;
}
if(n>1)
ans*=2*n-1;
printf("%lld\n",ans);
}
return 0;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
ll ans=0;
for(int i=1;i<=n/2+1;i++)
{
if(n%i==0)
{
ans+=(i*phi(n/i));
}
}
ans+=n;
printf("%lld\n",ans);
}
}
E - Happy 2006 POJ - 2773
题目大意:按升序找出与n互质的第k个数。
因为gcd(a,b)=gcd(a+kb,b)=d,推断可得与b互质的每个数具有周期性
核心代码
for(int i=1;i<=n;i++)
if(gcd(n,i)==1)
prime[res++]=i;
if(k%res)
cout<[k%res-1]<else
cout<<(k/res-1)*n+prime[res-1]<
H - X-factor Chains POJ - 3421
题目大意:就是给你一个数,要求你输出将这个数分解成因式相乘,并且后面一个因子至少是前面一个因子的2倍,问最长的因式相乘链有多长,有几条最长的因式相乘链。
其实就是一个排列组合题,由唯一分解定理得最长链长即为因子个数c,链条数即为k= c!e1!e2!⋅⋅⋅en! c ! e 1 ! e 2 ! · · · e n ! .
I - Pseudoprime numbers
判断素数+快速幂暴力即可
未完待续······
此外,积累几个极致筛素数和求逆元的方法
埃筛(利用素数倍数一定是合数来优化)
//O(nlognlogn) 埃筛--------------埃拉托斯特尼筛法,或者叫埃氏筛法
bool prime[a];
void init(){
for(int i=2;itrue;
for(int i=2;i*i//由for(int i=2;i
{
if(prime[i])
{
for(int j=i*i;j//由for(int j=i*2;j
prime[j]=false;
}
}
}
神奇的线性筛
//O(n) 线性筛
bool prime[maxn];//prime[i]表示i是不是质数
int p[maxn], tot=0;//p[maxn]用来存质数
void init(int a){
for(int i = 2; i <= a; i ++) prime[i] = true;//初始化为质数
for(int i = 2; i <= a; i++){
if(prime[i]) p[tot ++] = i;//把质数存起来
for(int j = 0; j < tot && i * p[j] <= a; j++){
prime[i * p[j]] = false;
if(i % p[j] == 0) break;//******保证每个合数被它最小的质因数筛去******
}
}
}
杜教筛???洲阁筛???以后再学吧
逆元线性筛 ( P为质数 )
求1,2,…,N关于P的逆元(P为质数)
复杂度:O(N)
const int mod = 1000000009;
const int maxn = 10005;
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
inv[i] = inv[mod % i] * (mod - mod / i) % mod;
没有互质限制
ans=a/b mod m=a mod(mb)/b;
阶乘逆元!
inv[maxn]=mod_pow(fac[maxn],mod-2);
for(ll i=maxn-1;i>=0;i--)
inv[i]=(inv[i+1]*(i+1))%mod;
还有什么莫比乌斯反演···那些等会了再更吧~
数学太难了!!!
这周总结先到这里,终于能睡一个>=6小时的觉了,明天开始图论专题,Fighting!!!