「解题报告」 [UOJ#62] 怎样跑得更快 (莫比乌斯反演)

「解题报告」 [UOJ#62] 怎样跑得更快 (莫比乌斯反演)

题意

给定 \(n,c,d\), 有 \(q\) 个询问, 每个询问给定 \(b_1,\cdots, b_n\), 满足

\[\sum_{j=1}^n\gcd(i,j)^c\cdot{\rm lcm}(i,j)^d\cdot x_j \equiv b_i \pmod p \]

对每个询问, 解出 \(x_1,\cdots,x_n\) 的值.


思路

目标 : 把原式转化为 \(f(x)=\sum_{d|x} g(d)\) 的形式, 然后用莫比乌斯反演求出 \(g(x)\).

下面的运算都是在 \(\mod p\) 意义下的运算.

\[\begin{align} b_i &= \sum_{j=1}^n\gcd(i,j)^c\cdot{\rm lcm}(i,j)^d\cdot x_j \\ &= \sum_{j=1}^n \gcd(i,j)^{c-d} \cdot (ij)^d \cdot x_j \\ &= \sum_{u|i} u^{c-d} \sum_{u|j}^n [\gcd(i,j)=u] \cdot (ij)^d \cdot x_j \\ &= \sum_{u|i} x^{c-d} \sum_{u|j}^n [\frac{\gcd(i,j)}{u}=1] \cdot (ij)^d \cdot x_j \\ &= \sum_{u|i} u^{c-d} \sum_{u|j}^n (ij)^d \cdot x_j \sum_{v|\frac{\gcd(i,j)}{u}} \mu(v)\\ &= \sum_{u|i} u^{c-d} \sum_{u|j}^n (ij)^d \cdot x_j \sum_{uv|gcd(i,j)} \mu(v)\\ \end{align} \]

\(T=uv\) (最关键的一步)

\[\begin{align} b_i &= \sum_{u|i} u^{c-d} \sum_{u|j}^n (ij)^d \cdot x_j \sum_{uv|gcd(i,j)} \mu(v) \\ &= \sum_{T|i}\sum_{T|j}^n (ij)^dx_j \sum_{u|T} u^{c-d}\mu\left(\frac{T}{u}\right) \end{align} \]

其中 \(\sum_{u|T} u^{c-d}\mu\left(\frac{T}{u}\right)\) 是两个积性函数的狄利克雷卷积, 可以线性筛出来, 设为 \(h(T)\), 则

\[\begin{align} b_i &= \sum_{T|i}\sum_{T|j}^n (ij)^dx_j \sum_{u|T} u^{c-d}\mu\left(\frac{T}{u}\right) \\ &= i^d \sum_{T|i}\sum_{T|j}^n j^d x_j h(T) \end{align} \]

\(\sum_{T|j}^n j^d x_j h(T)\)\(g(T)\), \(\frac{b_i}{i^d}\)\(f(i)\), 则

\[\begin{align} f(i)=\sum_{T|i} g(T) \\ \end{align} \]

利用莫比乌斯反演便可 \(O(n\sqrt n)\) 求出 \(g(x)\). 而

\[\begin{align} g(T)&=\sum_{T|j}^n j^d x_j h(T) \\ &\Downarrow \\ \frac{g(T)}{h(T)} &=\sum_{T|j}^n j^d x_j \\ &\Downarrow \\ x_T&=\frac{1}{T_d}\left( \sum_{T|j}^n \mu\left(\frac{j}{T} \right) \frac{g(j)}{h(j)}\right) \end{align} \]

便可在 \(O(n\log n)\) 内求出 \(x_n\).

总复杂度为 \(O(n+q(n+n\sqrt n+n\log n))\).

需要注意优化一下常数, 比如预处理 \(x^d\) 以及 \(x^{c-d}\).

代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int _=1e5+7;
const ll mod=998244353;
int n,T,pri[_],p[_];
ll C,D,mu[_],pw[2][_],f[_],g[_],h[_],a[_],b[_];
bool v[_],flag;
ll gi(){
  ll x=0,f=1; char c=getchar();
  while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
  while(isdigit(c)){ x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
  return x*f;
}
ll _pw(ll a,ll p){
  if(p<0) return _pw(_pw(a,-p),mod-2);
  ll res=1;
  while(p){
    if(p&1) res=res*a%mod;
    a=a*a%mod; p>>=1;
  }
  return res;
}
ll _inv(ll x){ return _pw(x,mod-2); }
void _pls(ll &x,ll y){ x=((x+y)%mod+mod)%mod; }
void _pre(){
  mu[1]=pw[0][1]=pw[1][1]=h[1]=p[1]=1;
  for(int i=2;i<=n;i++){
    if(!v[i]){
      v[i]=i; pri[++pri[0]]=i;
      mu[i]=-1;
      pw[1][i]=_pw(i,D);
      pw[0][i]=_pw(i,C)*_inv(pw[1][i])%mod;
      h[i]=((mu[i]+pw[0][i])%mod+mod)%mod;
      p[i]=i;
    }
    for(int j=1;j<=pri[0]&&i*pri[j]<=n;j++){
      v[i*pri[j]]=pri[j];
      pw[0][i*pri[j]]=pw[0][i]*pw[0][pri[j]]%mod;
      pw[1][i*pri[j]]=pw[1][i]*pw[1][pri[j]]%mod;
      if(!(i%pri[j])){
	mu[i*pri[j]]=0;
	p[i*pri[j]]=p[i]*pri[j];
	_pls(h[i*pri[j]],h[i/p[i]]*pw[0][p[i]]%mod*mu[pri[j]]%mod);
	_pls(h[i*pri[j]],h[i/p[i]]*pw[0][p[i*pri[j]]]%mod);
	break;
      }
      mu[i*pri[j]]=-mu[i];
      p[i*pri[j]]=pri[j];
      h[i*pri[j]]=h[i]*h[pri[j]]%mod;
    }
  }
  for(int i=1;i<=n;i++){
    h[i]=_inv(h[i]);
    pw[1][i]=_inv(pw[1][i]);
  }
}
void _run(){
  flag=0;
  for(int i=1;i<=n;i++){
    b[i]=gi(); f[i]=b[i]*pw[1][i]%mod;
    if(b[i]&&!pw[1][i]) flag=1;
  }   
  for(int i=1;i<=n;i++){
    g[i]=0;
    for(int j=1;j*j<=i;j++)
      if(!(i%j)){
	_pls(g[i],f[j]*mu[i/j]%mod);
	if(j*j!=i) _pls(g[i],f[i/j]*mu[j]%mod);
      }
    if(g[i]&&!h[i]){ flag=1; break; }
  }
  if(flag){ puts("-1"); return; }
  for(int i=1;i<=n;i++){
    ll a=0;
    for(int j=i;j<=n;j+=i)
      _pls(a,mu[j/i]*g[j]%mod*h[j]%mod);
    a=a*pw[1][i]%mod;
    printf("%lld ",a);
  }
  putchar('\n');
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("2.in","r",stdin);
  freopen("x.out","w",stdout);
#endif
  n=gi(); C=gi(); D=gi(); T=gi();
  _pre();
  while(T--)
    _run();
  return 0;
}


posted @ 2020-06-02 12:10  BruceW  阅读(236)  评论(0编辑  收藏  举报