#BSGS,哈希#洛谷 4884 多少个1

本文探讨了如何使用BSGS算法解决特定形式的模线性方程问题,即寻找最小正整数N,使重复N次的1构成的数等于K模m。通过乘法和加法变换,将问题转化为BSGS算法的标准形式,并提供了两种实现方式,包括使用unordered_map和手写哈希表的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给定整数KKK和质数mmm,求最小的正整数NNN,使得11⋯1(N个1)≡K(modm)11\cdots1(N个1)\equiv K \pmod m111(N1)K(modm)


分析

两边同乘9再加1得到
10n≡K∗9+1(modm)10^n\equiv K*9+1\pmod m10nK9+1(modm)
那么就是BSGS模板了


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <tr1/unordered_map>
#define rr register
using namespace std;
using namespace tr1;
typedef long long ll;
const ll trans=33554432;
inline void print(ll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline ll mo(ll a,ll b,ll mod){return a+b>=mod?a+b-mod:a+b;}
inline ll mul(ll a,ll b,ll mod){return mo(a*(b>>25)%mod*trans%mod,a*(b&(trans-1))%mod,mod);}
inline ll bsgs(ll a,ll b,ll mod){
	unordered_map<ll,ll>hash;
	rr int t=(int)sqrt(mod)+1; rr ll t1=1;
	for (rr ll j=0;j<t;++j)
		hash[mul(b,t1,mod)]=j,t1=mul(t1,a,mod);
	a=t1,t1=1;
	if (!a) return !b?1:-1;
	for (rr int i=0;i<=t;++i){
		rr int j=hash.find(t1)==hash.end()?-1:hash[t1];
		if (j>=0&&1ll*i*t>=j) return 1ll*i*t-j;
		t1=mul(t1,a,mod);
	}
	return -1;
}
signed main(){
	rr ll n,mod;
	scanf("%lld%lld",&n,&mod);
	print(bsgs(10,(9*n+1)%mod,mod));
	return 0;
}

upd:8.6
突然发现unordered_map太慢了,改成了手写哈希

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#define rr register
using namespace std;
const int p=397337;
typedef long long ll;
struct hash{
	struct node{int y; long long w; int next;}e[p]; int hs[p],tot;
	inline void clear(){memset(hs,0,sizeof(hs)); tot=0;}
	inline void add(int x,ll w){e[++tot]=(node){x,w%p,hs[w%p]},hs[w%p]=tot;}
	inline signed locate(ll x){
		for (rr int j=hs[x%p];j;j=e[j].next)
		    if (e[j].w==x) return e[j].y;
		return -1;
	}
}h;
inline void print(ll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline ll mo(ll a,ll b,ll mod){return a+b>=mod?a+b-mod:a+b;}
inline ll mul(ll a,ll b,ll mod){return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;}
inline ll bsgs(ll a,ll b,ll mod){
	h.clear();
	rr int t=sqrt(mod)+1; rr ll t1=1;
	for (rr ll j=0;j<t;++j)
	    h.add(j,mul(t1,b,mod)),t1=mul(t1,a,mod);
	a=t1,t1=1;
	if (!a) return !b?1:-1;
	for (rr int i=0;i<=t;++i){
		rr int j=h.locate(t1);
		if (j>=0&&1ll*i*t>=j) return 1ll*i*t-j;
		t1=mul(t1,a,mod);
	}
	return -1;
}
signed main(){
	rr ll n,mod;
	scanf("%lld%lld",&n,&mod);
	print(bsgs(10,(9*n+1)%mod,mod));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值