题库: https://cn.vjudge.net/contest/176263#overview
A:HDU 40704
做法:相当于将 n 任意组合, 可能的情况为 2^(n-1),因为n会很大,使用欧拉降幂公式
B:Given A,B,C, You should quickly calculate the result of A^B mod C. (1<=A,C<=1000000000,1<=B<=10^1000000).
做法:同上题一样算出C的欧拉数,做欧拉降幂
C:BZOJ 3884
做法:递归欧拉降幂。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll getoula(ll n)
{
if(n==1) return 0;
ll ans=n;
for(int i=2;i<=(int)sqrt(n+0.5);++i)
{
if(n%i==0)
{
ans = ans * (i-1) /i;
while(n%i==0) n/=i;
}
}
if(n>1) ans= ans * (n-1) /n;
return ans;
}
ll powermod(ll bit ,ll n, ll mod)
{
ll ans=1;
while(n)
{
if(n & 1) ans = (ans * bit) %mod;
bit = (bit * bit )%mod;
n>>=1;
}
return ans%mod;
}
ll f(ll p)
{
if(p==1) return 0;
int temp=getoula(p);
return powermod(2,f(temp)+temp,p);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll p;
scanf("%lld",&p);
printf("%lld\n",f(p));
}
return 0;
}
D POJ 2407
做法: 欧拉数水题
E POJ 2478
做法:筛发求欧拉数前缀和
F POJ 1845
做法:不难发现对于每个合适的sum等于其所有素数的等比数列和的积。
素数唯一定理,素数分解,等比数列递归求和,快速幂
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod = 9901;
ll powermod(ll bit,ll n,ll mod)
{
bit=bit % mod;
ll ans=1;
while(n)
{
if(n & 1) ans = (ans * bit) %mod;
bit = (bit * bit) %mod;
n>>=1;
}
return ans;
}
ll sum(ll p ,ll n,ll mod)
{
if(p==0) return 0;
if(n==0) return 1;
if(n&1) return ( ( 1+powermod(p,n/2+1,mod) )%mod * sum(p,n/2,mod)%mod )%mod;
else return ( (1+powermod(p,n/2+1,mod)) %mod *sum(p,n/2-1,mod)+powermod(p,n/2,mod)%mod)%mod;
}
const int maxn=10000;
bool book[maxn+10];
int prim[maxn+10],pnum=0;
void getprim()
{
memset(book,0,sizeof(book));
pnum=0;
book[1]=book[0]=1;
for(int i=2;i<=maxn;++i)
{
if(!book[i])
{
prim[pnum++]=i;
}
for(int j=0;j<pnum && prim[j]<=maxn/i ;++j)
{
book[prim[j]*i]=1;
if(i % prim[j]==0) break;
}
}
}
ll fact[105][2];
int fnum=0;
int getfact(ll x)
{
fnum=0;
ll temp=x;
for(int i=0;prim[i]<=temp/prim[i];++i)
{
fact[fnum][1]=0;
if(temp%prim[i]==0)
{
fact[fnum][0]=prim[i];
while(temp % prim[i]==0)
{
fact[fnum][1]++;
temp /=prim[i];
}
fnum++;
}
}
if(temp!=1)
{
fact[fnum][0]=temp;
fact[fnum++][1]=1;
}
return fnum;
}
int main()
{
ll a,b;
getprim();
while(scanf("%lld%lld",&a,&b)!=EOF)
{
getfact(a);
ll ans=1;
for(int i=0;i<fnum;++i)
{
ans = ( ans * sum( (ll)fact[i][0],(ll)b*fact[i][1],mod)%mod )%mod;
}
printf("%lld\n",ans);
}
return 0;
}
G POJ 1811
做法:大数的素数检验,如果是合数的话算出最小质因
模板:Miller_rabin + Pollard_rho
K POJ 1284
做法:欧拉数的应用, 一个存在原根的数的原根数 等于 Phi(Phi(n));
M POJ 3090
做法:很容易发现,图关于y=x这条线对称。 且 每次增加的为与前项gcd(i,n)为1的个数
ans = 1 +2* Sigmn Phi[i]。
N SPOJ 7001
题意:求GCD(X,Y,Z)=1 的种数 。
做法: 莫比乌斯函数反演,设 g(m)= GCD==x 的和 。 f(m) = GCD==kx 的和。 满足第二种莫比乌斯反演的形式
也不难发现 f(m)= [n/m]^3
记着考虑 X,Y,Z有 一个0 两个 0的情况
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=1000000;
bool book [maxn+5];
int prim[maxn+5];
int cnt=0;
int mu[maxn+5];
void getprim()
{
memset(book,1,sizeof(book));
cnt=0;
mu[1]=1;
for(int i=2;i<maxn ;++i)
{
if(book[i])
{
prim[cnt++] = i; mu[i]= -1;
}
for(int j=0;j<cnt && i*prim[j]<=maxn;++j)
{
book[i*prim[j]]=0;
if(i % prim[j]==0)
{
mu[i*prim[j]]=0;
break;
}
else
{
mu[i*prim[j]]= -mu[i];
}
}
}
}
int main()
{
getprim();
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
ll ans=3;
for(int i=1;i<=n;++i) ans +=(ll) mu[i]*(n/i)*(n/i)*(n/i + 3);
printf("%I64d\n",ans);
}
return 0;
}
HDU 1695
做法:求GCD(X,Y)==K 的种数 X属于(1,b) Y属于 (1,d)中 两边同除K。问题转换为 (1,b/K)(1,d/K)
求 GCD(x,y)==1; 和上一道题一样 直接莫比乌斯反演。
最后记着把 重复 的去掉
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100003;
bool book [maxn+5];
int p[maxn+5];
int mu[maxn+5];
int cnt=0;
void getprime()
{
memset(book,1,sizeof(book));
cnt=0;
mu[1]=1;
for(int i=2;i<maxn;++i)
{
if(book[i])
{
p[cnt++]=i; mu[i]= -1;
}
for(int j=0; j<cnt && i*p[j]<maxn;++j)
{
book[i*p[j]]=0;
if(i %p[j]==0)
{
mu[i *p[j]]= 0;
break;
}
else mu[i*p[j]] = -mu[i];
}
}
}
int main()
{
getprime();
int T;
int kiss=0;
scanf("%d",&T);
while(T--)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0)
{
printf("Case %d: 0\n",++kiss);
continue;
}
int x=(b/k);
int y=(d/k);
ll ans1=0;
for(int i=1;i<=min(x,y);++i)
{
ans1 = ans1 +(ll) mu[i] * (x/i) * (y/i);
}
ll ans2=0;
for(int i=1;i<=min(x,y);++i)
{
ans2 =ans2 +(ll) mu[i] * (min(x,y)/i) *(min(x,y)/i);
}
printf("Case %d: %I64d\n",++kiss,ans1-ans2/2);
}
return 0;
}
POJ 2417
做法:裸的离散对数 (BSGS)。