題庫: 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; }
#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)。