P5285骗分过样例——数论超级缝合怪

P5285 [十二省联考 2019] 骗分过样例

Case17:

ans[0]=1,ans[1]=19,ans[2]=361等可以看出是19n

Case1,2直接快速幂可过,Case3加个欧拉定理就行。 这里都有写到

Case4,5都是要猜模数,一个naive的想法就是找到输出数据中的最大值之后开始枚举模数,可以很快找到Case4的模数。

虽然我Case4114514后面加个数就试出来了

Case5就需要一点技巧了:

我选的方法如下:选择几对(x,y)(x<y),并使得yx尽可能小。

可以知道ans[y]ans[x]×19yx为模数的倍数,所以用python算几组数的最大公约数大致可以得到模数。

Case6,7:

众所周知,乘法不开long long会答案错误,而且有可能出现负数。

所以猜想这两组数据就是这样得到的,写个暴力就可以过Case6

Case7数据好大,而且快速幂的溢出是不对的(试试就知道了),怎么办呢?

这种可以由i推至i+1的可以试图找环,所以我们会想到用map来辅助找环。

经试验,会在第50000+项出现一个长度为50000+的环。

Case810:(rl106)

根据小样例和输出的字母p可以推出这部分是要筛出[l,r]内的质数。

这部分很简单,大数据直接用米勒来宾测试判断质数就行

Case1113:(rl106)

根据质数的地方都是-,有平方因子的都是0,字母u,可以猜测这部分是计算[l,r]内的莫比乌斯函数

Case11(l,r106)直接筛,Case12(l,r1012)是套路:筛出r内的质数,枚举它们在区间[l,r]的倍数,同时计算μ

Case13(l,r1018)只能筛到r3,还是枚举它们在区间[l,r]的倍数。

可以想到有一部分数会有[106,1018]内的质数因子(最多有两个),可以这么处理:

枚举倍数的同时对每个x算出它在[106,1018]内的质数因子的乘积yxx本身除掉[1,106]的质数因子即可)。

枚举倍数后分三类讨论:

  1. yx为完全平方数:μ(x)0
  2. yx为质数:μ(x)μ(x)
  3. 以上两种都不是,这种情况yx一定是两个不同质数的乘积(或者是1),不需要改μ(x)的值

注意这部分可能被卡常。

Case1416:

众所周知:998244353最小的原根是3,998244353=1+223×7×17

根据这个和g可以推断出是算出区间[l,r]p的原根。

Case14:质数p的原根x满足:mprime,m|p1,xp1m1(modp),用这个判断就行。

Case15:计算13123111的所有原根,用O(nlogloglogn)的计算方式即可。

Case16:需要猜模数,我感觉没什么好的方法,就写了如下代码:

#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的时间(2040min)就跑出来是1515343657,用Case14的方法就做完了

代码也就有亿点难写。

posted @   mod998244353  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
Live2D
欢迎阅读『P5285骗分过样例——数论超级缝合怪』
点击右上角即可分享
微信分享提示