P5285骗分过样例——数论超级缝合怪
\(\operatorname{Case} 1\sim7:\)
从\(ans[0]=1,ans[1]=19,ans[2]=361\)等可以看出是\(19^n\)
\(\quad\operatorname{Case} 1,2\)直接快速幂可过,\(\operatorname{Case} 3\)加个欧拉定理就行。 这里都有写到
\(\quad\operatorname{Case} 4,5\)都是要猜模数,一个\(naive\)的想法就是找到输出数据中的最大值之后开始枚举模数,可以很快找到\(\operatorname{Case} 4\)的模数。
虽然我\(\operatorname{Case}4\)在\(114514\)后面加个数就试出来了
\(\quad\operatorname{Case} 5\)就需要一点技巧了:
我选的方法如下:选择几对\((x,y) (x<y)\),并使得\(y-x\)尽可能小。
可以知道\(ans[y]-ans[x]\times 19^{y-x}\)为模数的倍数,所以用python
算几组数的最大公约数大致可以得到模数。
\(\quad\operatorname{Case} 6,7:\)
众所周知,乘法不开long long
会答案错误,而且有可能出现负数。
所以猜想这两组数据就是这样得到的,写个暴力就可以过\(\operatorname{Case} 6\)
\(\operatorname{Case} 7\)数据好大,而且快速幂的溢出是不对的(试试就知道了),怎么办呢?
这种可以由\(i\)推至\(i+1\)的可以试图找环,所以我们会想到用map
来辅助找环。
经试验,会在第\(50000+\)项出现一个长度为\(50000+\)的环。
\(\operatorname{Case} 8\sim 10:(r-l\leq10^6)\)
根据小样例和输出的字母p
可以推出这部分是要筛出\([l,r]\)内的质数。
这部分很简单,大数据直接用米勒来宾测试判断质数就行
\(\operatorname{Case} 11\sim 13:(r-l\leq10^6)\)
根据质数的地方都是-
,有平方因子的都是0
,字母u
,可以猜测这部分是计算\([l,r]\)内的莫比乌斯函数。
\(\quad\operatorname{Case} 11(l,r\leq10^6)\)直接筛,\(\operatorname{Case} 12(l,r\leq10^{12})\)是套路:筛出\(\sqrt{r}\)内的质数,枚举它们在区间\([l,r]\)的倍数,同时计算\(\mu\)
\(\quad\operatorname{Case} 13(l,r\leq10^{18})\)只能筛到\(\sqrt[3]{r}\),还是枚举它们在区间\([l,r]\)的倍数。
可以想到有一部分数会有\([10^6,10^{18}]\)内的质数因子(最多有两个),可以这么处理:
枚举倍数的同时对每个\(x\)算出它在\([10^6,10^{18}]\)内的质数因子的乘积\(y_x\)(\(x\)本身除掉\([1,10^6]\)的质数因子即可)。
枚举倍数后分三类讨论:
- \(y_x\)为完全平方数:\(\mu(x)\leftarrow0\)
- \(y_x\)为质数:\(\mu(x)\leftarrow-\mu(x)\)
- 以上两种都不是,这种情况\(y_x\)一定是两个不同质数的乘积(或者是\(1\)),不需要改\(\mu(x)\)的值
注意这部分可能被卡常。
\(\operatorname{Case} 14\sim 16:\)
众所周知:\(998244353\)最小的原根是\(3,998244353=1+2^{23}\times7\times17\)
根据这个和g
可以推断出是算出区间\([l,r]\)内\(p\)的原根。
\(\quad\operatorname{Case} 14:\)质数\(p\)的原根\(x\)满足:\(\forall m\in \operatorname{prime},m|p-1,x^{\frac{p-1}{m}}\not\equiv1\pmod p\),用这个判断就行。
\(\quad\operatorname{Case} 15:\)计算\(13123111\)的所有原根,用\(O(n\log\log\log n)\)的计算方式即可。
\(\quad\operatorname{Case} 16:\)需要猜模数,我感觉没什么好的方法,就写了如下代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAXN=1000002;
bool np[MAXN];
int prime[MAXN],pcnt,mu[MAXN];
set<int>v;
const int p[]= {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103},L=27;
inline ll mul(const ll&a,const ll&b,const ll&mod) {
ll r=((long double)a*b/mod+0.5);
r=a*b-r*mod;
return r<0?r+mod:r;
}
inline ull mr_fastpow(ull a,ull k,const ull&bigmod) {
ull base=1;
for(; k; k>>=1,a=mul(a,a,bigmod)) if(k&1)base=mul(base,a,bigmod);
return base;
}
inline bool mr(const ll n,const ll a) {
ll t=n-1;
while(!(t&1)) t>>=1;
ll buf=mr_fastpow(a,t,n);
if(buf==1||buf==n-1) return true;
while((t<<=1)<n-1) {
buf=mul(buf,buf,n);
if(buf==n-1) return true;
}
return false;
}
inline bool ptest(ll x) {
if(x==1) return false;
for(int i=1; i<=L; ++i)
if(!(x%p[i]))
return x==p[i];
return x<=10000ll?true:mr(x,2)&&mr(x,67)&&mr(x,233);
}
inline int fastpow(int a,int k,int mod) {
int base=1;
for(; k; k>>=1,a=a*1ll*a%mod) if(k&1)base=base*1ll*a%mod;
return base;
}
inline bool chker(int a,int P) {
int t=P-1;
for(int i=2; i*i<=t; ++i)
if(!(t%i)) {
t/=i;
if(fastpow(a,P/i,P)==1) return false;
while(!(t%i))t/=i;
}
if(t>1)if(fastpow(a,P/t,P)==1) return false;
return true;
}
//以上为米勒来宾质数测试
inline bool Chk(int x) {//判断x是否是质数且满足前11个数
return ptest(x)
&&!chker(233333333,x)
&&!chker(233333334,x)
&&!chker(233333335,x)
&& chker(233333336,x)
&& chker(233333337,x)
&& chker(233333338,x)
&&!chker(233333339,x)
&&!chker(233333340,x)
&& chker(233333341,x)
&& chker(233333342,x)
&&!chker(233333343,x);
}
inline bool Chk2(int x) {//判断x是否满足后20个数
for(int i=234133333,cnt=1; cnt<=20; ++cnt,--i)
if(chker(i,x)!=(cnt==3||cnt==8||cnt==10||cnt>18))
return false;
return true;
}
int a[100005],n;
int main() {
freopen("chk.txt","r",stdin);
freopen("chk.txt","w",stdout);
int l=1e9+1,r=2e9-1;
int cnt=0;
for(int i=l; i<=r; i+=2)//暴力枚举模数
if(Chk(i)&&Chk2(i))cout<<i<<endl;
return 0;
}
大约速通一次MC
的时间(\(20\sim40\min\))就跑出来是\(1515343657
\),用\(\operatorname{Case} 14\)的方法就做完了
代码也就有亿点难写。