P8459

bs 鸽鸽的小清新题,我来发篇摸鱼验题人题解。

首先考虑极低分做法,分别是 模拟列竖式FFT,复杂度分别是 O(n2)O(n^2)O(nlogn)O(n\log n),都过不了。

其次考虑一些奇怪的语言,比如知名的自带高精的 Python 以及 Ruby(后者似乎慢些),但是他们实现的方法毕竟不是 O(n)O(n) 的,根据亲测,Ruby 和 Python 均能得到 15pts 的高分,但是都寄在了最后一点。

接下来考虑正解,根据上述的努力和高达 10710^7 级的数据我们知道只能搞 O(n)O(n) 的做法,然后关键点在于找到一种 O(n)O(n) 的高精度运算之后我们处理运算完之后的小数据,得出判断。

取舍了一通之后发现高精模低精好像十分靠谱,因为有式子:aa1(modp),bb1(modp)a×ba1×b1(modp)a\equiv a_1\pmod {p},b\equiv b_1\pmod {p}\Rightarrow a\times b\equiv a_1\times b_1\pmod {p},但是它并不保证反着也是正确的。

那么怎么证明它的可靠性呢?我们考虑如果毒瘤出题人要卡一个模数的话他就要用 CRT 构造,可以知道如果在 101810^{18} 的范围内取模数的话它只有极小的概率会被卡。

那么实现就很简单了,高精模低精,然后随机一个或多个模数进行计算,多模数的话如果结果均正确就 OK 了。

bs 鸽鸽写的是单模数且不随机的做法,理论上是可以卡的,实际上毒瘤出题人卡掉了 998244353,1917998244353,19****171616 个常用模数,实际上如果发现模数被卡就再换一个呗,比如 53075307 就没有被卡(

当然,模数越多常数越大,你写 66 模数应该是能稳定地跑过去,77 模数由于常数和评测机状态的问题可能就会被卡了,当然,谁没事干写那么多模数的啊 除了我为了看看 bs 的数据多毒瘤(

由于模数太多影响可读性,这里放一个三模数的代码:

#include<bits/stdc++.h>
using namespace std;
// #define int long long
int mod1,mod2,mod3;
int t;
struct Node{
	int x,y,z;
};
inline Node read(){
	int s1=0,s2=0,s3=0;char ch=getchar();
	while(!isdigit(ch)){ch=getchar();}
	while(isdigit(ch)){
		s1=s1*10+(ch^48);
		s2=s2*10+(ch^48);
		s3=s3*10+(ch^48);
		if(s1>mod1)s1%=mod1;
		if(s2>mod2)s2%=mod2;
		if(s3>mod3)s3%=mod3;
		ch=getchar();
	}
	return (Node){s1,s2,s3};
}
signed main(){
	cin>>t;
	srand(time(0));
	while(t--){
		mod1=rand()%(int)1e4,mod2=rand()%(int)1e4,mod3=rand()%(int)1e4;
		Node a=read(),b=read(),c=read();
		if(a.x*b.x%mod1==c.x&&a.y*b.y%mod2==c.y&&a.z*b.z%mod3==c.z)puts("YES");
		else puts("NO");
	}
	return 0;
}

最后说下怎么卡模数,比如 bs 鸽鸽曾经的题解用的模数是 123123,那么我们随便写两个数,比如 533×622=331526533\times622=331526,模 1231234141,那么构造

1
533 622 41

就能卡掉力!

比如我们同时卡 1231231212,那么 $331526\equiv 2\pmod{12} $,然后构造 41+123×3=41041+123\times3=410,它模 121222,模 1231234141,所以就可以卡掉双模数了,多模数同理。

当然,不要叉 bs 的,bs 可爱。