bs 鸽鸽的小清新题,我来发篇摸鱼验题人题解。
首先考虑极低分做法,分别是 模拟列竖式 和 FFT,复杂度分别是 和 ,都过不了。
其次考虑一些奇怪的语言,比如知名的自带高精的 Python 以及 Ruby(后者似乎慢些),但是他们实现的方法毕竟不是 的,根据亲测,Ruby 和 Python 均能得到 15pts 的高分,但是都寄在了最后一点。
接下来考虑正解,根据上述的努力和高达 级的数据我们知道只能搞 的做法,然后关键点在于找到一种 的高精度运算之后我们处理运算完之后的小数据,得出判断。
取舍了一通之后发现高精模低精好像十分靠谱,因为有式子:,但是它并不保证反着也是正确的。
那么怎么证明它的可靠性呢?我们考虑如果毒瘤出题人要卡一个模数的话他就要用 CRT 构造,可以知道如果在 的范围内取模数的话它只有极小的概率会被卡。
那么实现就很简单了,高精模低精,然后随机一个或多个模数进行计算,多模数的话如果结果均正确就 OK 了。
bs 鸽鸽写的是单模数且不随机的做法,理论上是可以卡的,实际上毒瘤出题人卡掉了 等 个常用模数,实际上如果发现模数被卡就再换一个呗,比如 就没有被卡(
当然,模数越多常数越大,你写 模数应该是能稳定地跑过去, 模数由于常数和评测机状态的问题可能就会被卡了,当然,谁没事干写那么多模数的啊 除了我为了看看 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 鸽鸽曾经的题解用的模数是 ,那么我们随便写两个数,比如 ,模 是 ,那么构造
1
533 622 41
就能卡掉力!
比如我们同时卡 和 ,那么 $331526\equiv 2\pmod{12} $,然后构造 ,它模 是 ,模 是 ,所以就可以卡掉双模数了,多模数同理。
当然,不要叉 bs 的,bs 可爱。