现在有一个由n个珠子组成的项链,满足相邻两个珠子不同。
每个珠子可以看做三个数组成的序列,需要满足三个数最大公约数为1且每个数不大于m,两个珠子如果经过旋转或翻转完全一致则认为其相同。
现在求不同项链数,两个项链如果经过旋转完全一致则认为其相同。
答案模10^9+7.
n<=10^14,m<=10^7
太麻烦了看Crazy的吧
Crazy的项链题解
程序我写的比较优美所以贴我的。
注意n比模数大,但注意到n的因子中最多只含有一个模数。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll maxn=10000000+10;
const ll mo=1000000007;
ll pri[maxn],miu[maxn],sum[maxn],c[maxn];
bool bz[maxn];
ll i,j,k,l,t,m,ca,top,tot,cnt;
ll n,p,t2,t3,ans,b[maxn];
ll quicksortmi(ll x,ll y){
if (!y) return 1;
ll t=quicksortmi(x,y/2); t=t*t%mo; if (y%2) t=t*x%mo; return t; } ll f(ll n){ ll t=(cnt-1)*quicksortmi(-1,n)%mo; t=(t+mo)%mo; t=(t+quicksortmi(cnt-1,n))%mo; return t; } void dfs(ll x,ll y,ll z){ if (x==tot+1){ ans=(ans+f(n/y)*(z%mo)%mo)%mo; //printf("%lld\n",ans); return; } dfs(x+1,y,z); ll i; ll j=1; fo(i,1,c[x]){ j*=b[x]; dfs(x+1,y*j,z*j/b[x]*(b[x]-1));
}
}
int main(){
miu[1]=sum[1]=1;
fo(i,2,maxn-10){
if (!bz[i]) pri[++top]=i,miu[i]=-1;
fo(j,1,top){
if ((ll)i*pri[j]>maxn-10) break;
bz[i*pri[j]]=1;
if (i%pri[j]==0){
miu[i*pri[j]]=0;
break;
}
miu[i*pri[j]]=-miu[i];
}
sum[i]=sum[i-1]+miu[i];
}
scanf("%lld",&ca);
while (ca--){
scanf("%lld%lld",&n,&m);
p=n;
tot=0;
fo(i,1,top){
if (p==1) break;
if (p%pri[i]==0){
b[++tot]=pri[i];
c[tot]=0;
while (p%pri[i]==0){
p/=pri[i];
c[tot]++;
}
}
}
if (p>1) b[++tot]=p,c[tot]=1;
//p=mo*mo;
t3=t2=0;
i=1;
while (i<=m){
j=m/(m/i);
t3=(ll)(t3+(ll)(m/i)*(m/i)%mo*(m/i)%mo*(sum[j]-sum[i-1])%mo)%mo;
t3=(ll)(t3+mo)%mo;
t2=(ll)(t2+(ll)(m/i)*(m/i)%mo*(sum[j]-sum[i-1])%mo)%mo;
t2=(ll)(t2+mo)%mo;
i=j+1;
}
cnt=(ll)(t3+3*t2%mo+2)*quicksortmi(6,mo-2)%mo;
ans=0;
dfs(1,1,1);
if (n%mo==0) ans=ans*quicksortmi(n/mo,mo-2)%(mo*mo)/mo%mo;
else{
n%=mo;
ans=ans*quicksortmi(n,mo-2)%mo;
}
ans=(ans%mo+mo)%mo;
printf("%lld\n",ans);
}
}