UR#5 怎样跑得更快

Posted An_Fly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UR#5 怎样跑得更快相关的知识,希望对你有一定的参考价值。

给你整数 \\(n,c,d\\) ,现在有整数 \\(x_1,…,x_n\\)\\(b_1,…,b_n\\)

满足:

\\[\\sum_{j=1}^n\\gcd(i,j)^clcm(i,j)^dx_j≡b_i\\pmod p \\]

给出 \\(b_1,…,b_n\\),请你解出 \\(x_1,…,x_n\\) 的值。

直接推式子,有

\\[\\begin{aligned} \\sum_{j=1}^n\\gcd(i,j)^clcm(i,j)^dx_j&=\\sum_{j=1}^n\\gcd(i,j)^{c-d}i^dj^dx_j\\\\ &=i^d\\sum_{j=1}^n\\gcd(i,j)^{c-d}j^dx_j\\\\ \\end{aligned} \\]

\\(x_j=j^dx_j\\),这样最后再除掉一个 \\(j^d\\) 即可,所以现在得到了一个系数是和 \\(\\gcd\\) 有关的方程组,令 \\(F(x)=x^{c-d}\\),那么将方程组写成一个矩阵的形式,大概是下边这样的。

\\[\\begin{bmatrix} F(\\gcd(1,1))& F(\\gcd(1,2)) & F(\\gcd(1,3)) & F(\\gcd(1,4)) \\\\ F(\\gcd(2,1)) & F(\\gcd(2,2)) & F(\\gcd(2,3)) & F(\\gcd(2,4)) \\\\ F(\\gcd(3,1)) & F(\\gcd(3,2)) & F(\\gcd(3,3)) & F(\\gcd(3,4)) \\\\ F(\\gcd(4,1)) & F(\\gcd(4,2)) & F(\\gcd(4,3)) & F(\\gcd(4,4)) \\end{bmatrix} \\]

暴力做当然是直接高斯消元,不过注意到对于这种矩阵,一个事情是它可以直接消元消成一种比较好看的形式。

\\(F(x)=\\sum_{d|x}G(d)\\),那么原来的第 \\(i\\) 行第 \\(j\\) 列变成了 \\(\\sum_{d|i,d|j}G(d)\\),现在证明经过若干次初等行变换可以得到一个新矩阵,该矩阵的第 \\(i\\) 行第 \\(j\\) 列为 \\([i|j]G(i)\\)

使用归纳法证明,显然第一行不用任何变换就满足,对于其它行,只需要减去除了它以外的所有因子的行即可。

所以最后可以得到一个比较简单的矩阵。

\\[\\begin{bmatrix} G(\\gcd(1,1))& G(\\gcd(1,2)) & G(\\gcd(1,3)) & G(\\gcd(1,4)) \\\\ 0 & G(\\gcd(2,2)) & 0 & G(\\gcd(2,4)) \\\\ 0 & 0 & G(\\gcd(3,3)) & 0 \\\\ 0 & 0 & 0 & G(\\gcd(4,4)) \\end{bmatrix} \\]

对这个矩阵手动消一下元就能够得到每一个 \\(x_j\\) 的值。

判断无解和多组解的方法跟高斯消元一样。

#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define ll long long
#define rll register long long
const int N=1e5+10;
const int p=998244353;
ll fpow(rll a,rll b){
	rll res=1;
	for(;b;b>>=1,a=a*a%p)
		if(b&1)res=res*a%p;
	return res;
}
ll b[N],g[N];
int main(){
	rint n,c,d,q;
	scanf("%d%d%d%d",&n,&c,&d,&q);
	while(q--){
		for(rint i=1;i<=n;i++){
			scanf("%lld",&b[i]);
			b[i]=b[i]*fpow(fpow(i,d),p-2)%p;
		}
		for(rint i=1;i<=n;i++)
			g[i]=fpow(i,p-1+(c-d)%(p-1));
		for(rint i=1;i<=n;i++){
			for(rint j=i+i;j<=n;j+=i){
				g[j]=(g[j]-g[i]+p)%p;
				b[j]=(b[j]-b[i]+p)%p;
			}
			if(!g[i]&&b[i]){
				puts("-1");
				goto E;
			}
			b[i]=b[i]*fpow(g[i],p-2)%p;
		}
		for(rint i=n;i;i--){
			for(rint j=i+i;j<=n;j+=i)
				b[i]=(b[i]-b[j]+p)%p;
		}
		for(rint i=1;i<=n;i++)
			b[i]=b[i]*fpow(fpow(i,d),p-2)%p;
		for(rint i=1;i<=n;i++)
			printf("%lld ",b[i]);
		puts("");E:;
	}
	return 0;
}

以上是关于UR#5 怎样跑得更快的主要内容,如果未能解决你的问题,请参考以下文章

UOJ #62. UR #5怎样跑得更快

杂题选放

[UOJ62]怎样跑得更快

让Python跑得更快

10条SQL优化语句,让你的MySQL数据库跑得更快!

我可以让 Java 跑得更快吗? [关闭]