洛谷·[SDOI2013] 随机数生成器

初见安~这里是传送门:洛谷P3306 [SDOI2013] 随机数生成器

题解

显然我们可以写出一个式子:

x_n=a^{n-1}x_1+b\sum_{i=0}^{n-2}a^i \equiv t (mod \ p)

后面一坨等比数列求和:

a^{n-1}x_1+b*\frac{1-a^{n-1}}{1-a} \equiv t

简单移项:

a^{n-1} \equiv \frac{t(1-a)-b}{x_1(1-a)-b}

于是这就是一个BSGS的板子了。而且p还是质数。

然后你就可以获得全WA的好成绩【?

因为这个题真正毒的地方在于特判……

我们回头再看看我们的推导过程:

首先对等比数列求和。等等,这真的是等比数列么?

a=0的时候,是个等差数列。这个必须特判。

a=1的时候,是常值。这个情况看似直接用t-x1除以b就好,但是除数部分就只剩下b了。b也可能为0

上述特判后,这个题就可以过了。

复杂度O(T\sqrt n),上代码——

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#define maxn 100005
using namespace std;
typedef long long ll;
int read() {
	int x = 0, f = 1, ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
	while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
	return x * f;
}

int T, mod, a, b, x1, t, sq;
map<int, int> mp;
int pre[maxn];
int pw(int a, int b) {int res = 1; while(b) {if(b & 1) res = 1ll * res * a % mod; a = 1ll * a * a % mod, b >>= 1;} return res;}
signed main() {
	T = read();
	while(T--) {
		mod = read(), a = read(), b = read(), x1 = read(), t = read();
		if(x1 == t) {puts("1"); continue;}
		if(!a) {if(t == x1) puts("1"); else if(t == b) puts("2"); else puts("-1"); continue;}
		if(a == 1) {
			if(!b) puts("-1");
			else printf("%d\n", 1ll * (t - x1 + mod) * pw(b, mod - 2) % mod + 1);
			continue;
		}//好了特判完了。
		
		sq = sqrt(mod); mp.clear();
		b = (1ll * t * (1 - a + mod) % mod - b + mod) % mod * pw(1ll * x1 * (1 - a + mod) % mod - b + mod, mod - 2) % mod;
		pre[0] = 1; register int tmp = 1; mp[1] = 0;
		for(int i = 1; i <= sq; i++) {//BSGS预处理根号内的值
			tmp = 1ll * tmp * a % mod;
			if(!mp[tmp]) mp[tmp] = i;
		}
		tmp = pw(pw(a, sq), mod - 2);//其实完全不必预处理的……
		for(int i = 1; i <= sq; i++) pre[i] = 1ll * pre[i - 1] * tmp % mod;
		
		bool flag = false;
		for(int i = 0; i <= sq; i++) {//ans=i*sqrt()+j 枚举i
			tmp = 1ll * b * pre[i] % mod;//记得+1 因为求的是n-1
			if(mp[tmp] || tmp == 1) {printf("%d\n", i * sq + mp[tmp] + 1); flag = true; break;}
		}
		if(!flag) puts("-1");
	}
}

迎评:)
——End——

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值