题目:
题意:
给定,;求出下面又长又难看的式子的值:
分析:
首先从简单的推一下(纯属自己娱乐):
那么原式就可以化简成如下形式:
把最后面的一堆设成函数g(L),再看这个式子中间的部分,就是一个等比数列,而向下取整的值是一块一块的,每一块是相等的,可以利用这个性质加速,那么我们还得快速计算出g(L1) - g(L2),设S(n)为g(L)的前n项和,那么就等价于S(L1) - S(L2);这个函数的前缀和就得用杜教筛快速求出;容易看出g函数是莫比乌斯函数和单位函数id^2的狄利克雷卷积的形式,而莫比乌斯函数卷上恒等函数等于元函数,设h(n) = (g*I)(n),则h(n) = id(n)^2 = n^2,(这部分有点水,熟悉了再来填坑)即得到:
利用上式即可完成杜教筛部分,等比数列求和可用欧拉降幂公式简化,注意公比为1的情况(这时求和答案为k-1,应对mod取余)
代码:
#include <bits/stdc++.h>
#define sz(x) (int)(x).size()
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int maxn = 1e6+16;
const int inv6 = 166666668;
map<int,int> mp;
string s;
int ans[maxn],mob[maxn],prime[maxn],vis[maxn];
void init(){ //O(nlogn)预处理g函数的部分前缀和
mob[1] = 1;int cnt = 0;
for(int i = 2;i < maxn; ++i){
if(!vis[i]) prime[cnt++]=i,mob[i]=-1;
for(int j = 0;j < cnt&&1ll*i*prime[j]<maxn; ++j){
vis[i*prime[j]] = 1;
if(i%prime[j] == 0){
mob[i*prime[j]] = 0;
break;
}
else mob[i*prime[j]] = -1*mob[i];
}
}
for(int i = 1;i < maxn; ++i){
for(int j = i;j < maxn; j+=i){
ans[j] += ((1ll*j/i)*(1ll*j/i)%mod*mob[i]%mod+mod)%mod;
if(ans[j] >= mod) ans[j] -= mod;
}
}
for(int i = 1;i < maxn; ++i){
ans[i] += ans[i-1];
if(ans[i] >= mod) ans[i] -= mod;
}
}
LL qpow(LL a,LL x,LL mod){
LL res = 1; a%=mod;
while(x){
if(x & 1) res = res*a % mod;
a = a*a % mod;
x >>= 1;
}
return res;
}
LL inv(LL a,LL mod){
return qpow(a,mod-2,mod);
}
LL cal1(int n){ //杜教筛
if(n < maxn) return ans[n];
if(mp.count(n)) return mp[n];
LL res = 0;
for(int i = 2,last;i <= n; i=last+1){
int tep = n/i; last = n/tep;
res += 1ll*(last-i+1)*cal1(tep)%mod;
if(res>=mod) res -= mod;
}
return mp[n] = (1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod-res+mod)%mod;
}
LL cal2(LL q,LL n,LL nn){ //等比数列求和
if(q == 1) return (nn-1+mod)%mod;
return inv(q-1,mod)*(qpow(q,n+1,mod)-q*q%mod+mod)%mod;
}
LL solve(LL n){
LL res = 0,k = 0,kk = 0;
for(int i = 0;i < sz(s); ++i){
k = (k*10+(s[i]-'0'))%(mod-1);
kk = (kk*10+(s[i]-'0'))%mod;
}
for(int i = 1,last;i <= n; i=last+1){
int tep = n/i; last = n/tep;
res += cal2(tep,k,kk)*(cal1(last)-cal1(i-1)+mod)%mod;
if(res >= mod) res -= mod;
}
return res%mod;
}
int main(){
int T,n;
init(); cin >> T;
while(T--){
cin >> n >> s;
cout << solve(n) << '\n';
}
return 0;
}