题目描述
あの日の悲しみさえ
那一天的悲伤也好
あの日の苦しみさえ
那一天的痛苦也好
そのすべてを愛してた あなたとともに
我深爱着和你在一起的点点滴滴
胸に残り離れない
残留在心中久久不离
苦いレモンの匂い
苦柠檬的香气
雨が降り止むまでは帰れない
雨停为止都无法回去
切り分けた果実の片方の様に
如同切开的果实的一面那样
今でもあなたはわたしの光
至今为止你依然是我的光
米津玄师—《Lemon》
旧日的美好已如昙花般绽放之后消失的无影无踪,只剩下些许的回忆和无穷的悔恨。如梦般的时光已经逝去,但值得庆幸的是,仍有电脑、鼠标、键盘和那一串串的公式无言却忠诚地记录着过去。
小D在时光的缝隙中找到了一个公式
x = ∏ i = 1 q p i k i , g ( x ) = ∑ i = 1 q k i , g ( 1 ) = 1 x=\prod_{i=1}^qp_i^{k_i},g(x)=\sum_{i=1}^qk_i,g(1)=1 x=∏i=1qpiki,g(x)=∑i=1qki,g(1)=1
g ( p r i m e ) = 1 , g ( a × p r i m e ) = g ( a ) + 1 g(prime)=1,g(a\times prime)=g(a)+1 g(prime)=1,g(a×prime)=g(a)+1所以线性筛的时候,可以顺便把 g ( n ) g(n) g(n)给筛出来。
入门推荐:here
原式子: ∏ i = 1 n ∏ j = 1 m g ( g c d ( i , j ) ) \prod_{i=1}^n\prod_{j=1}^m g(gcd(i,j)) i=1∏nj=1∏mg(gcd(i,j))
提取 g c d gcd gcd: ∏ d = 1 n g ( d ) ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] \prod_{d=1}^n g(d)^{\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]} d=1∏ng(d)∑i=1n∑j=1m[gcd(i,j)=d]
反演一下指数那个式子: ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] = ∑ i = 1 n d ∑ j = 1 m d [ g c d ( i , j ) = 1 ] = ∑ i = 1 n d ∑ j = 1 m d ∑ k ∣ g c d ( i , j ) μ ( k ) \sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]=\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md}[gcd(i,j)=1]=\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md}\sum_{k|gcd(i,j)}\mu(k) i=1∑nj=1∑m[gcd(i,j)=d]=i=1∑dnj=1∑dm[gcd(i,j)=1]=i=1∑dnj=1∑dmk∣gcd(i,j)∑μ(k)
得到这个式子: ∏ d = 1 n g ( d ) ∑ k = 1 n d μ ( k ) n k d m k d \prod_{d=1}^n g(d)^{\sum_{k=1}^{\frac nd}\mu(k)\frac{n}{kd}\frac{m}{kd}} d=1∏ng(d)∑k=1dnμ(k)kdnkdm
上面这个式子可以 O ( n ) O(n) O(n)求值了,但是还不够,因为这题有多组数据。
想到一个常用的优化方式:
先把指数提下来: ∏ d = 1 n ∏ k = 1 n d g ( d ) μ ( k ) n k d m k d \prod_{d=1}^n \prod_{k=1}^{\frac nd} g(d)^{\mu(k)\frac{n}{kd}\frac{m}{kd}} d=1∏nk=1∏dng(d)μ(k)kdnkdm
令 T = k d T=kd T=kd,换元求积: ∏ T = 1 n ∏ d ∣ T g ( d ) μ ( T d ) n T m T \prod_{T=1}^n\prod_{d|T}g(d)^{\mu(\frac Td)\frac nT \frac mT} T=1∏nd∣T∏g(d)μ(dT)TnTm
再变换一下: ∏ T = 1 n ( ∏ d ∣ T g ( d ) μ ( T d ) ) n T m T \prod_{T=1}^n(\prod_{d|T}g(d)^{\mu(\frac Td)})^{\frac nT \frac mT} T=1∏n(d∣T∏g(d)μ(dT))TnTm
发现这个式子 ∏ d ∣ T g ( d ) μ ( T d ) \prod_{d|T}g(d)^{\mu(\frac Td)} ∏d∣Tg(d)μ(dT)可以 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))预处理出来, O ( 1 ) O(1) O(1)求值。
所以最后总的复杂度是 O ( ( n l o g ( n ) + T n ) × 常 数 ) O((nlog(n)+T\sqrt n)\times常数) O((nlog(n)+Tn)×常数)
AC_CODE:
#include
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false);cin.tie(0)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const int MXN = 3e5 + 6;
int n, q, m;
int noprime[MXN], pp[MXN/2], pcnt;
int mu[MXN];
LL g[MXN], inv_g[MXN], f[MXN], pre[MXN], inv_pre[MXN];
LL ksm(LL a, LL b) {
LL res = 1;
for(;b;b>>=1,a=a*a%MOD) {
if(b&1) res=res*a%MOD;
}
return res;
}
void init_rime() {
noprime[0] = noprime[1] = 1;
mu[1] = g[1] = 1;
for(int i = 2; i < MXN; ++i) {
if(!noprime[i]) pp[pcnt++] = i, mu[i]=-1, g[i] = 1;
for(int j = 0; j < pcnt && i*pp[j] < MXN; ++j) {
noprime[i*pp[j]] = 1;
mu[i*pp[j]] = -mu[i];
g[i*pp[j]] = g[i] + 1;
if(i % pp[j] == 0) {
mu[i*pp[j]] = 0;
break;
}
}
}
for(int i = 1; i < MXN; ++i) f[i] = 1, inv_g[i] = ksm(g[i], MOD-2);
for(int i = 2; i < MXN; ++i) {
for(int j = i; j < MXN; j += i) {
if(mu[j/i] == 1) f[j] = f[j] * g[i] % MOD;
else if(mu[j/i] == -1) f[j] = f[j] * inv_g[i] % MOD;
}
}
pre[0] = pre[1] = inv_pre[0] = inv_pre[1] = 1;
for(int i = 2; i < MXN; ++i) {
pre[i] = pre[i-1] * f[i] % MOD;
inv_pre[i] = ksm(pre[i], MOD-2);
}
}
int main(int argc, char const *argv[]) {
init_rime();
int tim;
scanf("%d", &tim);
while(tim --) {
scanf("%d%d", &n, &m);
LL ans = 1, tmp;
if(n > m) swap(n, m);
for(int L = 1, R; L <= n; L = R + 1) {
R = min(n/(n/L),m/(m/L));
ans = (ans * ksm(pre[R]*inv_pre[L-1]%MOD, 1LL*(n/L)*(m/L)%(MOD-1)))%MOD;
}
printf("%lld\n", ans);
}
return 0;
}
题目类似:bzoj 4816: [Sdoi2017]数字表格