• 【bzoj3122】 Sdoi2013—随机数生成器


    http://www.lydsy.com/JudgeOnline/problem.php?id=3122 (题目链接)

    题意

      对于一个数列${X_i}$,其递推式为:${X_{i+1}=(a*X_i+n)~mod~P}$,求最小的${i}$满足${X_i=t}$。

    Solution

      大家还记得数学中数列那一章吗,那么推倒这个数列的方法一定是老师重点强调过的:

    $${X_{i+1}+λ=a*(X_i+λ)}$$

    $${可以算出λ=frac{b}{a-1}}$$

    $${令B_i=X_i+frac{b}{a-1}}$$

    $${则B_{i+1}=a*B_i,为等比数列}$$

    $${B_i=B_1*a^{i-1}}$$

    $${B_i=(X_1+frac{b}{a-1})*a^{i-1}}$$

    $${ecause B_i=X_i+frac{b}{a-1}}$$

    $${ herefore X_i=(X_1+frac{b}{a-1})*a^{i-1}-frac{b}{a-1}}$$

    $${令c=(a-1)^{-1}~(mod~p)}$$

    $${则X_i=(X_1+b*c)*a^{i-1}+b*c~~(mod~p)}$$

    $${即求(X_1+b*c)*a^{i-1}≡t-b*c~~(mod~p)}$$

      因为a的取值,我们需要考虑特殊情况并进行分类讨论。

      首先要特判${X_1=t}$的情况,因为这个在后面不好处理,不如讨论之前就直接排除在外。

      1.${a=0}$

      这种情况下要么是${t=X_1}$,要么是${t=X_2}$,因为${X_n=b~(n>1)}$

      2.${a=1}$

      那么数列就可以简化为:${X_{i+1}=X_i+b}$,是一个等差数列。

      即求:${X_1+b*(i-1)=t~(mod~p)}$

      这可以用exgcd求解。

      3.${a>=2}$

      那么就是我们上面推下来的式子,先用exgcd求出${a^{i-1}}$的最小正整数解,然后用BSGS计算${i-1}$的取值。

    细节

      数学题就是细节多,exgcd判无解。

    代码

    // bzoj3122
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    map<LL,LL> mp;
    
    LL power(LL a,LL b,LL c) {
    	LL res=1;
    	while (b) {
    		if (b&1) res=res*a%c;
    		b>>=1;a=a*a%c;
    	}
    	return res;
    }
    LL BSGS(LL a,LL b,LL p) {
    	LL m=ceil(sqrt(p));
    	LL inv=power(a,p-1-m,p),e=1;
    	mp.clear();mp[1]=0;
    	for (int i=1;i<m;i++) {
    		e=e*a%p;
    		if (!mp.count(e)) mp[e]=i;
    	}
    	for (int i=0;i<m;i++) {
    		if (mp.count(b)) return mp[b]+i*m+1;
    		b=b*inv%p;
    	}
    	return -1;
    }
    void exgcd(LL a,LL b,LL &d,LL &x,LL &y) {
    	if (b==0) {d=a;x=1;y=0;return;}
    	exgcd(b,a%b,d,y,x);
    	y-=a/b*x;
    }
    int main() {
    	LL P,A,B,X1,t;
    	int T;scanf("%d",&T);
    	while (T--) {
    		scanf("%lld%lld%lld%lld%lld",&P,&A,&B,&X1,&t);		
    		if (X1==t) {puts("1");continue;}   //一定要特判,如果进入BSGS后b为0出来的解是-1
    		if (A==0) {
    			if (B==t) puts("2");
    			else puts("-1");
    		}
    		if (A==1) {
    			LL x,d,y;
    			t=(t-X1)%P;if (!t) {puts("1");continue;}
    			exgcd(B,P,d,x,y);
    			if (t%d!=0) {puts("-1");continue;}
    			printf("%lld
    ",((t/d)*x%(P/d)+(P/d))%(P/d)+1);
    		}
    		if (A>=2) {
    			LL x,d,y;
    			LL c=power(A-1,P-2,P);
    			t=(t+B*c)%P;
    			exgcd(X1+B*c,P,d,x,y);
    			if (t%d!=0) {puts("-1");continue;}
    			x=((t/d)*x%(P/d)+(P/d))%(P/d);
    			printf("%lld
    ",BSGS(A,x,P));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    用Python完成Excel的常用操作
    用Python实现excel 14个常用操作
    ubuntu and centos各种上网代理设置
    vim 熟练度练习
    Ansible-playbook 使用方式 看一篇就够了
    python 使用ldap3 查询跨域的用户信息
    python pyinstaller 的使用
    vs code新建python虚拟环境
    vs code 远程开发环境设置
    上下文管理器(Context Manager)
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6207861.html
Copyright © 2020-2023  润新知