【UR #5】怎样跑得更快

题目

给定\(n,c,d\)和序列\(\{b_i\}\),求一个序列\(\{x_i\}\)满足

\[\sum_{j=1}^n\gcd(i,j)^c\times \rm{lcm(i,j)^d}\times x_j\equiv b_i(mod\ P ) \]

不难将\(\rm lcm(i,j)\)写成\(\frac{i\times j}{\gcd(i,j)}\)

\[\sum_{j=1}^n\gcd(i,j)^{c-d}j^dx_j\equiv b_i\times i^{-d}(mod\ P) \]

套路枚举\(\gcd\),之后套路反演一下,设\(\omega =c-d\)

\[\sum_{d|i}d^{\omega}\sum_{d|k}[k|i]\mu(\frac{k}{d})F(k)\equiv b_i\times i^{-d}(mod\ P) \]

其中\(F(k)=\sum_{k|t}x_tt^d\)

套路地进行简单和式变换

\[\sum_{k|i}F(k)\sum_{d|k}\mu(\frac{k}{d})d^{\omega}\equiv b_i\times i^{-d}(mod\ P) \]

\(g(n)=\sum_{d|n}\mu(\frac{n}{d})d^{\omega}\)

上式即为

\[\sum_{k|i}F(k)g(k)\equiv b_i\times i^{-d}(mod\ P) \]

不难发现就是一个函数叫做\(F(k)g(k)\)卷上了一个\(1\)得到了右边那个函数,不妨称之为\(B(i)\)

\(F(i)g(i)=(\mu\times B)(i)\)

于是\(F(i)=\frac{(\mu\times B)(i)}{g(i)}\),得到\(F\)之后再和\(\mu\)卷一波就能求\(x\)

\(\mu\)完全可以用高维差分优化到\(O(n\log \log n)\),所以要是写个线筛\(i^k\)和离线求逆元就是\(O(qn\log \log n)\)复杂度了

显然我懒得写

代码

#include<bits/stdc++.h>
#define re register
const int maxn=1e5+5;
const int mod=998244353;
inline int dqm(int x){return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int f[maxn],p[maxn>>1],b[maxn],g[maxn],n,c,d;
inline int ksm(int a,int b) {
	b%=(mod-1);if(b<0) b+=mod-1;
	int S=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) S=1ll*S*a%mod;return S;
}
inline void work() {
	for(re int i=1;i<=n;i++) b[i]=1ll*read()*ksm(i,-d)%mod;
    for(re int i=1;i<=p[0];++i) 
		for(re int j=n/p[i];j;--j) b[j*p[i]]=dqm(b[j*p[i]]-b[j]);
	for(re int i=1;i<=n;i++)
		if(g[i]==0&&b[i]) {puts("-1");return;}else b[i]=1ll*b[i]*g[i]%mod;
	for(re int i=1;i<=p[0];++i)
		for(re int T=n/p[i],j=1;j<=T;++j) b[j]=dqm(b[j]-b[p[i]*j]);
	for(re int i=1;i<=n;i++) printf("%d ",1ll*b[i]*ksm(i,-d)%mod);
	puts("");
}
int main() {
	n=read(),c=read(),d=read();c%=(mod-1),d%=(mod-1);
	for(re int i=2;i<=n;i++) {
		if(!f[i]) p[++p[0]]=i;
		for(re int j=1;j<=p[0]&&p[j]*i<=n;++j) {
			f[p[j]*i]=1;if(i%p[j]==0)break;
		}
	}
	for(re int i=1;i<=n;i++) g[i]=ksm(i,c-d);
	for(re int i=p[0];i;--i)
		for(re int j=n/p[i];j;--j) g[p[i]*j]=dqm(g[p[i]*j]-g[j]);	
	for(re int i=1;i<=n;i++) g[i]=ksm(g[i],mod-2);
	for(re int Q=read();Q;--Q) work();return 0;
}
posted @ 2019-12-12 08:35  asuldb  阅读(301)  评论(1)    收藏  举报