原博文网址链接:http://www.cnblogs.com/oldmanren/archive/2012/11/23/2784986.html
Problem Zero:[neerc2011]Gcd guessing game
现在有一个数x,1 ≤ x≤ n,告诉你n,每次你可以猜一个数y,如果x==y则结束,否则返回gcd(x,y),问最少只要几次就可以保证猜出答案。
求出1-n中所有素数,及其不大于n的最高幂次,另y是所有质数最高幂次的乘积,则gcd(x,y)=x,因此最少一次就可以得到结果
Problem One:[CQOI2007 余数之和sum]sigma(K%i),1 ≤ i ≤ n
sigma(K%i)=sigma(K-(K/i)*i),K/i可以在i连续时合并,因此只要算最多K/i的可能取值数目次就可以得到结果
结论1:K/i(1<=i<=n)最多有O(sqrt(k))个不同取值
证明:1.i=sqrt(k)时,K/i约等于sqrt(K),又K/i是递减的,因此i>sqrt(K)时,K/i的取值最多只有sqrt(K)种。即使1<=i<=sqrt(K)时K/i全都不同,总共K/i的取值也就2*sqrt(K)种,因此计算量为O(sqrt(K))
结论2:在[i,K/(K/i)]这一段区间内,K/i的值相等
类似结论:b%(a%b)
证明:设x=a%b=b/2,b-x<=b/2,所以b%x
problem2-4是关于欧拉函数的应用,略去。
Problem Five:[双亲数/POI Zap(多组)]求gcd(i, j) == d (i ≤ a, j ≤ b) 的对数
题目解析见笔记本,代码如下
int t,a,b,d;
int mu[maxn],pri[maxn],sumu[maxn],cnt;
bool not_prime[maxn];
void mobius(){//筛法求莫比乌斯函数
mu[1]=1;
for(int i=2;i<=maxn;i++){
if(!not_prime[i]) pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++){
not_prime[i*pri[j]]=1;
if(i%pri[j]==0) { mu[i*pri[j]]=0;break; }
else mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=maxn;i++) sumu[i]=sumu[i-1]+mu[i];
}
int cal(int n,int m){
if(n>m) swap(n,m);
int ans=0,tmp;
for(int i=1;i<=n;i=tmp+1){//sigma(K/i)(i>=1)分块合并求和---problem one
tmp=min(n/(n/i),m/(m/i));
ans+=(sumu[tmp]-sumu[i-1])*(n/i)*(m/i);
}
return ans;
}
int main(){
mobius();
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&a,&b,&d);
printf("%d\n",cal(a/d,b/d));
}
return 0;
}
Problem Six:[SPOJ PGCD/BZOJ2820YY的GCD(多组)]
求gcd(i, j)是质数, 1 ≤ i ≤ a, 1 ≤ j ≤ b 的对数
思路:仿照PROBLEM FIVE可以得到g函数的递推式,在筛法中可以求出g,再分块求和即可
代码如下:#include
#include
#include
#define maxn 50010
using namespace std;
int t,a,b,d;
int mu[maxn],pri[maxn],sumg[maxn],g[maxn],cnt;
bool not_prime[maxn];
void mobius(){
mu[1]=1;
for(int i=2;i<=maxn;i++){
if(!not_prime[i]) { pri[++cnt]=i,mu[i]=-1;g[i]=1; }
for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++){
not_prime[i*pri[j]]=1;
if(i%pri[j]==0) { mu[i*pri[j]]=0;g[i*pri[j]]=mu[i];break; }
else { mu[i*pri[j]]=-mu[i];g[i*pri[j]]=mu[i]-g[i]; }
}
}
for(int i=1;i<=maxn;i++) sumg[i]=sumg[i-1]+g[i];
}
int cal(int n,int m){
if(n>m) swap(n,m);
int ans=0,tmp;
for(int i=1;i<=n;i=tmp+1){
tmp=min(n/(n/i),m/(m/i));
ans+=(sumg[tmp]-sumg[i-1])*(n/i)*(m/i);
}
return ans;
}
int main(){
mobius();
scanf("%d",&t);
while(t--){
scanf("%d%d",&a,&b);
printf("%d\n",cal(a,b));
}
return 0;
}
通过莫比乌斯变换或欧老公式求和逆变换变形后,变成sigma([n/t]*[m/t]*phi(t)),1<=t<=min(a,b)。代码如下
#include
#include
#include
#define maxn 100010
#define ll long long
using namespace std;
ll n,m;
ll prime[maxn],cnt,phi[maxn],sump[maxn];
bool not_prime[maxn];
void Phi(){
phi[1]=1;
for(ll i=2;i<=maxn;i++){
if(!not_prime[i]) prime[++cnt]=i,phi[i]=i-1;//素数初始化
for(ll j=1;j<=cnt&&i*prime[j]<=maxn;j++){
not_prime[i*prime[j]]=1;
if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j];break; }
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(ll i=1;i<=n;i++) sump[i]=sump[i-1]+phi[i];
}
ll cal(ll n,ll m){//sigma[gcd(i,j)],1<=i<=n,1<=j<=m
if(n>m) swap(n,m);
ll ans=0,tmp;
for(ll i=1;i<=n;i=tmp+1){
tmp=min(n/(n/i),m/(m/i));
ans+=(sump[tmp]-sump[i-1])*(n/i)*(m/i);
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
Phi();
printf("%lld\n",2*cal(n,m)-m*n);
return 0;
}
Problem Eight:[Crash的数字表格/BZOJ2693 jzptab(多组)]
sigma(lcm(i, j)) ,i ≤ a, j ≤ b
利用莫比乌斯变换化简,跑了11s,也是醉了...
#include
#include
#include
#define maxn 10000100
#define ll long long
#define anti4 15075757
const ll mod=20101009;
using namespace std;
ll t,a,b;
ll n,ans,pri[maxn],cnt,f[maxn];
bool np[20101050];
void mobius(){
f[1]=1;
for(ll i=2;i<=n;i++){
if(!np[i]) pri[++cnt]=i,f[i]=((1-i)%mod+mod)%mod;
for(ll j=1;j<=cnt&&pri[j]*i<=n;j++){
np[i*pri[j]]=1;
if(i%pri[j]==0) { f[i*pri[j]]=f[i];break; }
else f[i*pri[j]]=((f[i]%mod*(1-pri[j])%mod)%mod+mod)%mod;
}
}
for(ll i=1;i<=n;i++) f[i]=((f[i-1]%mod+i%mod*f[i]%mod)%mod+mod)%mod;
}
ll cal(ll a,ll b){
if(a>b) swap(a,b);
ll ans=0,tmp;
for(ll i=1;i<=a;i=tmp+1){
tmp=min(a/(a/i),b/(b/i));
ans=((ans%mod+((f[tmp]-f[i-1])%mod+mod)%mod*(a/i)%mod*(a/i+1)%mod*(b/i)%mod*(b/i+1)%mod)%mod+mod)%mod;
}
return (ans*anti4)%mod;
}
int main(){
scanf("%lld%lld",&a,&b);
n=max(a,b);
mobius();
printf("%lld\n",cal(a,b));
return 0;
}
Problem Nine:[BZOJ2694LCM]:
sigma(lcm(i, j)),i ≤ a, j ≤ b,gcd(i,j)为free-squares.(所有质因子的次数<=1)
莫比乌斯逆变换,用逆变换的函数解原函数不易解决的问题,结合gcd函数的运算技巧,可以化简出结果。
和Problem Eight写法类似,代码略
Problem Nine:[BZOJ2694LCM]:
sigma(lcm(i, j)),i ≤ a, j ≤ b,gcd(i,j)为free-squares.(所有质因子的次数<=1)