卧薪尝胆,厚积薄发。
UR5 怎样跑得更快
Date: Wed Dec 12 11:36:00 CST 2018 In Category: NoCategory

Description:

给出 $n,c,d$ ,多次询问,每次给出 $b_1,b_2,\dots,b_n$ ,求一组 $x_1,x_2,\dots,x_n$ 满足: $$ \sum_{j=1}^n\gcd(i,j)^c\times \text{lcm}(i,j)^d\times x_j\equiv b_i\mod p $$ $1\leqslant n\leqslant 10^5$

Solution:

首先把 $\text{lcm}$ 拆开,就是: $$ \sum_{j=1}^n\gcd(i,j)^{c-d}i^dj^d\times x_j\equiv b_i $$ 我们可以把这个式子抽象一下: $$ \sum_{j=1}^nf(\gcd(i,j))g(i)h(j)\times x^j=b_i $$ 那么我们构造 $f_r(i)$ 满足: $$ \sum_{d|n}f_r(d)=f(n) $$ 这个 $f_r$ 可以像 $O(n\ln n)$ 求狄利克雷卷积那样倒着求,也就是说: $$ f_r(n)=f(n)-\sum_{d|n,d\ne n}f_r(d) $$ 于是递推就可以了。
那么式子变成了: $$ \sum_{j=1}^n\sum_{d|i,d|j}f_r(d)h(j)\times x^j=b_i/g(i) $$ 套路交换求和号: $$ \sum_{d|i}f_r(d)\sum_{j=1,d|j}^nh(j)\times x_j=b_i/g(i) $$ 设 $v(d)=f_r(d)\sum_{j=1,d|j}^nh(j)\times x_j$ ,显然有 $v\times 1=b_i/g(i)$ ,于是莫比乌斯反演即可得到 $v$ ,具体做法是像上面一样 $O(n\ln n)$ 求,再除 $f_r$ 就可以得到 $z(d)=\sum_{j=1,d|j}^nh(j)\times x_j$ ,再莫比乌斯反演即可得到 $x_j$ ,有一些细节看代码。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,q;
#define MAXN 100010
typedef long long ll;
ll b[MAXN];
ll fr[MAXN];
ll z[MAXN];
ll c,d;
#define MOD 998244353
ll power(ll a,ll b)
{
ll res = 1;
while(b > 0)
{
if(b & 1)res = res * a % MOD;
a = a * a % MOD;
b = b >> 1;
}
return res;
}
int main()
{
scanf("%d%lld%lld%d",&n,&c,&d,&q);
for(int i = 1;i < MAXN;++i)fr[i] = power(i,(c - d + MOD - 1) % (MOD - 1));
for(int i = 1;i < MAXN;++i)for(int j = i + i;j < MAXN;j += i)fr[j] = (fr[j] - fr[i] + MOD) % MOD;
while(q--)
{
for(int i = 1;i <= n;++i)scanf("%lld",&b[i]);
for(int i = 1;i <= n;++i)z[i] = b[i] * power(power(i,d),MOD - 2) % MOD;
for(int i = 1;i <= n;++i)for(int j = i + i;j <= n;j += i)z[j] = (z[j] - z[i] + MOD) % MOD;
bool tag = false;
for(int i = 1;i <= n;++i)if(fr[i] == 0 && z[i] != 0)tag = true;
if(tag){puts("-1");continue;}
for(int i = 1;i <= n;++i)z[i] = z[i] * power(fr[i],MOD - 2) % MOD;
for(int i = n;i >= 1;--i)for(int j = i + i;j <= n;j += i)z[i] = (z[i] - z[j] + MOD) % MOD;
for(int i = 1;i <= n;++i)z[i] = z[i] * power(power(i,d),MOD - 2) % MOD;
for(int i = 1;i <= n;++i)printf("%lld ",(z[i] + MOD) % MOD);
puts("");
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡