UR #5 怎样跑得更快

首先推出来这样一个东西:

\[b_i=\sum\limits_{j=1}^n\gcd(i,j)^{C-D}\cdot i^D\cdot j^D\cdot x_j \]

现在令:

\[\begin {aligned} b_i &= \frac {b_i} {(i^D)} \\ x_i &= x_i*i^D \end {aligned} \]

考虑\(C=1,D=0\)怎么做

\[\begin {aligned} b_i &= \sum _j \sum _{d|gcd(i,j)} \phi (d) x_j \\ &=\sum_{d|i} \phi(d)\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}x_{d*j} \end{aligned} \]

\[y_i = \sum _{j=1}^{\lfloor\frac{n}{i}\rfloor}x_i \]

\[g_i=\phi(i)*y_i \\ b_i = \sum _{d|i} g_d \\ g_i = \sum _{d|i} b_d\mu(i/d) \]

\(C=1,D=0\)就可以过了

现在考虑其他的情况,我们考虑构造一个函数F,使得:

\[p_i=i^{C-D}=\sum _{d|i} f_d \]

同样反演:

\[f_d = \sum_{d|i}p_d\mu(i/d) \]

把F和G求出来就有y了,然后还原成x输出就行。

无解的情况就是除的时候非0除0。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
inline int qinv(int x){return qpow(x,mod-2);}
/* math */
const int N = 1e5+5;
int pcnt,prime[N],v[N],mu[N];
typedef vector<int> diric;
diric dirichlet_mul(diric a,diric b){
	diric c(a.size(),0);int n=a.size()-1;
	for(int i=1;i<=n;i++)for(int j=i;j<=n;j+=i)
		c[j]=add(c[j],mul(a[i],b[j/i]));
	return c;
}
diric transform(diric a){
	diric c(a.size(),0);int n=a.size()-1;
	for(int i=1;i<=n;i++)for(int j=i;j<=n;j+=i)
		c[i]=add(c[i],mul(a[j],mu[j/i]));
	return c;
}
int n,c,d,q;
diric x,y,g,MU,b,tot;

inline void sieve(int n){
	mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!v[i])mu[i]=mod-1,prime[++pcnt]=i;
		for(int j=1;j<=pcnt&&1ll*i*prime[j]<=n;j++){
			int nxt=i*prime[j];v[nxt]=1;
			if(i%prime[j])mu[nxt]=mod-mu[i];
			else {
				mu[nxt]=0;
				break;
			}
		}
	}
	MU.resize(n+1);
	for(int i=1;i<=n;i++)MU[i]=mu[i];
}

int main()
{
	cin >> n >> c >> d >> q;
	sieve(n);
	g.resize(n+1);
	for(int i=1;i<=n;i++){
		g[i]=((c-d>=0)? qpow(i,c-d) : qinv(qpow(i,d-c)));
	}
	g=dirichlet_mul(g,MU);
	while(q--){
		bool EXIT=0;
		y.resize(n+1);
		b.resize(n+1);
		for(int i=1;i<=n;i++)scanf("%d",&b[i]), b[i]=mul(b[i],qinv(qpow(i,d)));
		tot=dirichlet_mul(b,MU);
		for(int i=1;i<=n;i++){
			y[i]=mul(tot[i],qinv(g[i]));
			if(tot[i]!=0 && g[i]==0){
				printf("-1\n");EXIT=1;break;
			}
		}
		if(EXIT)continue;
		x=transform(y);
		for(int i=1;i<=n;i++)printf("%d ",mul(x[i],qinv(qpow(i,d))));puts("");
	}
}
posted @ 2019-06-13 23:54  jerome_wei  阅读(235)  评论(0)    收藏  举报