[LOJ3050][数论]十二省联考:骗分过样例

LOJ3050
首先说明下每个点要干嘛:
1_998244353:求19的k次幂,对998244353取模,k可能很大,大到longlong装不下(真押韵)
1?(+):求19的k次幂,模数未知,要自己去猜,一个模数比较小,另一个很大,在longlong范围内
1wa_998244353:求19的k次幂,对998244353取模,但是观察输出数据发现有负数,再根据题目提示和wa判断是爆int了,k在longlong范围内
2p:区间判断质数,longlong范围内
2u:区间求 μ \mu μ,longlong范围内
2g:区间求是否是给出的数的原根
2g?:同2g,给出的数未知

Solution:

1_998244353:快速幂
对于k很大的情况,用费马小定理降幂
1?:首先求出输出文件里面最大的数是多少,然后往上枚举看是不是模数就行了
1?+:模数很大,但是我们可以找到 k 1 , k 2 k1,k2 k1,k2,使 k 2 − k 1 k2-k1 k2k1尽量小,然后记下它们对应的答案为 a n s 1 , a n s 2 ans1,ans2 ans1,ans2,则有
a n s 1 ∗ 1 9 k 2 − k 1 ≡ a n s 2 ( % m o d ) ans1*19^{k2-k1}\equiv ans2(\%mod) ans119k2k1ans2(%mod)
a n s 1 ∗ 1 9 k 2 − k 1 − a n s 2 ≡ 0 ( % m o d ) ans1*19^{k2-k1}-ans2\equiv 0(\%mod) ans119k2k1ans20(%mod)
然后mod就是前面那一堆的一个因数
多找几个这样的,求个gcd就行了

1wa_998244353:
直接用wa的办法乘,但是不能快速幂,k又很大
wa是有循环的,用个map找找循环就好了

2p:miller_rabin
2 μ \mu μ:首先筛出 1 − 1 e 6 1-1e6 11e6的质数,然后把区间的每个数的 1 − 1 e 6 1-1e6 11e6的因子筛掉
则剩下的部分要么是完全平方数,要么是质数,要么是两个大于1e6的质数乘起来,要么是1,miller_rabin下就好了
2g:第一个点直接暴力求原根
第二个点 13123111 − 1 = 2 ∗ 3 ∗ 5 ∗ 7 ∗ 11 ∗ 13 ∗ 19 ∗ 23 13123111-1=2*3*5*7*11*13*19*23 131231111=235711131923,筛一下不是原根的数
第三个点就暴力跑,猜p就好了

这题真是神题

Code:

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
inline ll read(){
	ll res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
char op[15];
inline ll mul(ll x,ll y,ll m){return (x*y-m*(ll)((long double)x*y/m+0.5)+m)%m;}
inline ll ksm(ll a,ll b,ll mod){ll res=1;for(;b;b>>=1,a=mul(a,a,mod)) if(b&1) res=mul(res,a,mod);return res;}
inline int wa_mul(register int a,int b,int mod){return a*b%mod;}
const int N=1e6+7;
int pt[N],pri[N],tot=0;
inline void init(){
	pt[1]=1;
	for(register int i=2;i<=N-7;++i){
		if(!pt[i]) pri[++tot]=i;
		for(register int j=1;j<=tot && i*pri[j]<=N-7;++j){
			pt[i*pri[j]]=1;
			if(i%pri[j]==0) break;
		}
	}
}
int prii[6]={0,2,3,5,7,29};
inline bool miller(ll x,int tim=5){
	if(x<=N-7) return !pt[x];
	if(x%2==0) return false;
	ll t=x-1,s=0;
	while(!(t&1)) ++s,t>>=1;
	for(register int i=1;i<=tim;++i){
		ll p=prii[i]%x;
		ll num=ksm(p,t,x),tmp=num;
		for(register int j=0;j<s;++j){
			num=mul(num,num,x);
			if(num==1 && tmp!=1 && tmp!=x-1) return false;
			tmp=num;
		}
		if(num!=1) return false;
	}
	return true;
}
namespace l_998244353{
	inline ll readk(register int mod){
		ll res=0;char ch=getchar();
		while(!isdigit(ch)) ch=getchar();
		while(isdigit(ch)) {res=(mul(res,10,mod)+(ch^48))%mod;ch=getchar();}
		return res;
	}
	inline void work(){
		if(op[1]!='w'){
			ll mod;
			if(op[1]=='_') mod=998244353;
			else if(op[1]=='?' && op[2]=='+') mod=5211600617818708273ll;
			else mod=1145141;
			int n=read();
			while(n--){
				ll k=readk(mod-1);
				cout<<ksm(19,k,mod)<<"\n";
			}
		}
		else{
			map<int,int>mp;
			vector<int>vec;
			int st,ed;
			vec.pb(1);
			for(register int i=1,x=19;;++i,x=wa_mul(x,19,998244353)){
				if(mp.find(x)==mp.end()) mp[x]=i,vec.pb(x);
				else {st=mp[x],ed=i;break;}
			}
			int n=read();
			while(n--){
				ll x=read();
				if(x<st) cout<<vec[x]<<"\n";
				else cout<<vec[st+(x-st)%(ed-st)]<<"\n";
			}
		}
	}
}
namespace two{
	inline void p(){
		int n=read();
		while(n--){
			ll l=read(),r=read();
			for(ll i=l;i<=r;++i) miller(i)?putchar('p'):putchar('.');
			puts("");
		}
	}
	ll mu[N],tt[N];
	inline void u(){
		int n=read();
		while(n--){
			ll l=read(),r=read();
			for(register int j=0;j<=r-l;++j) mu[j]=tt[j]=1;
			for(register int j=1;j<=tot;++j){
				for(ll k=l/pri[j];k<=r/pri[j];++k){
					if(k*pri[j]-l<0) continue;
					if(k%pri[j]) mu[k*pri[j]-l]*=-1,tt[k*pri[j]-l]*=pri[j];
					else mu[k*pri[j]-l]=0; 
				}
			}
			for(ll j=l;j<=r;++j){
				if(mu[j-l]){
					ll x=j/tt[j-l];
					if(x==1);
					else if((ll)sqrt(x)*(ll)sqrt(x)==x) mu[j-l]=0;
					else if(miller(x,1)) mu[j-l]*=-1;
				}
				if(!mu[j-l]) cout<<mu[j-l];
				else putchar(mu[j-l]==1?'+':'-');
			}
			puts("");
		}
	}
	int pt[13123122],f[13123122];
	inline void g(){
		int n=read(),mod;
		while(n--){
			int l=read(),r=read();
			if(l==233333333) mod=1515343657;
			else mod=read();
			if(mod==998244353) for(register int i=l;i<=r;++i) (ksm(i,mod/2,mod)==1 || ksm(i,mod/7,mod)==1 || ksm(i,mod/17,mod)==1)?putchar('.'):putchar('g');
			else if(mod==13123111){
				for(register int i=1,g=6;i<mod;++i,g=g*6%mod) f[g]=i;
				int p[]={2,3,5,7,11,13,19,23};
				for(register int j=0;j<8;++j)
					for(register int i=p[j];i<=mod;i+=p[j]) pt[i]=1;
				for(register int i=l;i<=r;++i) pt[f[i]]?putchar('.'):putchar('g');
			}
			else for(register int i=l;i<=r;++i) (ksm(i,mod/2,mod)==1 || ksm(i,mod/3,mod)==1 || ksm(i,mod/4003,mod)==1 || ksm(i,mod/15773,mod)==1)?putchar('.'):putchar('g');
			puts("");
		}
	}
}
int main(){
	srand(time(0));
	init();
	cin>>op;
	if(op[0]=='1') l_998244353::work();
	else if(op[1]=='p') two::p();
	else if(op[1]=='u') two::u();
	else two::g();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值