zoukankan      html  css  js  c++  java
  • 洛谷 P3306 【随机数生成器】


    观察题目,易得出暴力代码,但是会TLE,只能得20pts

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 int T;
     5 ll a, b, x1, t, p, ans;
     6 int main()
     7 {
     8     scanf("%d", &T);
     9     while(T--)
    10     {
    11         ans = 0;
    12         scanf("%lld %lld %lld %lld %lld", &p, &a, &b, &x1, &t);
    13         while(233)
    14         {
    15             ++ans;
    16             if(ans > p)
    17             {
    18                 puts("-1");
    19                 break;
    20             }
    21             if(x1 == t)
    22             {
    23                 printf("%lld
    ", ans);
    24                 break;
    25             }
    26             x1 = (x1 * a + b) % p;
    27         }
    28     }
    29     return 0;
    30 }
    View Code

    考虑展开式子。

    由$x[i$ $+$ $1]$ $≡$ $a$ $*$ $x[i]$ $+$ $b$ $(mod$ $p)$得

    $x[1]$ $=$ $x1$ $\%$ $p;$

    $x[2]$ $=$ $(a$ $*$ $x1$ $+$ $b)$ $\%$ $p;$

    $x[3]$ $=$ $(a$2 $*$ $x1$ $+$ $a$ $*$ $b$ $+$ $b)$ $\%$ $p;$

    $x[4]$ $=$ $(a$3 $*$ $x1$ $+$ $a$2 $*$ $b$ $+$ $a$ $*$ $b$ $+$ $b)$ $\%$ $p;$

    $x[5]$ $=$ $(a$4 $*$ $x1$ $+$ $a$3 $*$ $b$ $+$ $a$2 $*$ $b$ $+$ $a$ $*$ $b$ $+$ $b)$ $\%$ $p;$

    $……$

    $x[k]$ $=$ $(a$k - 1 $*$ $x1$ $+$ $a$k - 2 $*$ $b$ $+$ $a$k - 3 $*$ $b$ $+$ $......$ $+$ $a$2 $*$ $b$ $+$ $a$ $*$ $b$ $+$ $b)$ $\%$ $p;$

    题目中求在第几天看到了第$t$页,如果永远也看不到就输出$-1$,否则输出最早的一天。

    不妨设在第$k$天看到了第$t$页,于是可得方程:

    $x[k]$ $≡$ $t$ $(mod$ $p);$

    $a$k - 1 $*$ $x1$ $+$ $a$k - 2 $*$ $b$ $+$ $a$k - 3 $*$ $b$ $+$ $......$ $+$ $a$2 $*$ $b$ $+$ $a$ $*$ $b$ + $b$ $≡$ $t$ $(mod$ $p);$

    其中,$a、x1、b、t、p$已知,求解$k$的值。

    先不看第一项$a$k - 1 $*$ $x1$,容易发现其余项是一个等比数列。

    提出$b$:

    $a$k - 1 $*$ $x1$ $+$ $b$ $*$ $(a$k - 2 $+$ $a$k - 3 $+$ $......$ $+$ $a$2 $+$ $a$ $+$ $1)$ $≡$ $t$ $(mod$ $p);$

    求解$a$k - 2 $+$ $a$k - 3 $+$ $......$ $+$ $a$2 $+$ $a$ $+$ $1$的值可以代入等比数列求和公式

    解得:

    当$a$ $=$ $1$时,原式 $=$ $k$ $-$ $1$;

    当$a$ $≠$ $1$时,原式 $=$ $(1$ $-$ $a$k - 1) $/$ $(1$ $-$ $a);$

    代入原方程可得:

    当$a$ $=$ $1$时,原方程为:

    $x1$ $+$ $b$ $*$ $(k$ $-$ $1)$ $≡$ $t$ $(mod$ $p);$

    $x1$ $+$ $bk$ $-$ $b$ $≡$ $t$ $(mod$ $p);$

    $bk$ $≡$ $t$ $+$ $b$ - $x1$ $(mod$ $p);$

    当$a$ $≠$ $1$时,原方程为:

    $a$k - 1 $*$ $x1$ $+$ $b$ $*$ $(1$ $-$ $a$k - 1$)$ $/$ $(1$ $-$ $a)$ $≡$ $t$ $(mod$ $p);$

    $a$k - 1 $*$ $x1$ $*$ $(1$ $-$ $a)$ $+$ $b$ $*$ $(1$ $-$ $a$k - 1$)$ $≡$ $t$ $*$ $(1$ $-$ $a)$ $(mod$ $p);$

    $a$k - 1 $*$ $(x1$ $-$ $x1$ $*$ $a)$ $+$ $b$ $-$ $b$ $*$ $a$k - 1 $≡$ $t$ $-$ $t$ $*$ $a$ $(mod$ $p);$

    $a$k - 1 $*$ $(x1$ $-$ $x1$ $*$ $a$ $-$ $b)$ $≡$ $t$ $-$ $t$ $*$ $a$ $-$ $b$ $(mod$ $p);$

    $a$k - 1 $≡$ $(t$ $-$ $t$ $*$ $a$ $-$ $b)$ $*$ $(x1$ $-$ $x1$ $*$ $a$ $-$ $b)$-1 $(mod$ $p);$(这里的$-1$次方表示逆元)

    整理得:

    当$a$ $=$ $1$时,$bk$ $≡$ $t$ $+$ $b$ $-$ $x1$ $(mod$ $p);$

    当$a$ $≠$ $1$时,$a$k - 1 $≡$ $(t$ $-$ $t$ $*$ $a$ $-$ $b)$ $*$ $(x1$ $-$ $x1$ $*$ $a$ $-$ $b)$-1 $(mod$ $p);$

    易看出:

    当$a$ $=$ $1$时,可以用$exgcd$求解出$k$;

    当$a$ $≠$ $1$时,可以用$BSGS$求解出$k$;

    有一些需要特判的坑点在代码里:

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 #define ll long long 
     4 using namespace std;
     5 int T;
     6 ll a, b, p, x, y, ps, d, x1, t;
     7 map < ll, ll > mp;
     8 void exgcd(ll a, ll b, ll &x, ll &y)
     9 {
    10     if(!b) x = 1, y = 0, d = a;
    11     else exgcd(b, a % b, y, x), y -= x * (a / b);
    12     return;
    13 }
    14 ll ksm(ll x, ll y, ll mod)
    15 {
    16     ll ans = 1;
    17     for(; y; y >>= 1)
    18     {
    19         if(y & 1) ans = ans * x % mod;
    20         x = x * x % mod;
    21     }
    22     return ans;
    23 }
    24 ll bsgs(ll a, ll b, ll p)
    25 {
    26     mp.clear();//记得清空 
    27     b = (b % p + p) % p;//b可能是负数 
    28     if(a == b) return 1;//特判a == b 
    29     ps = ceil((double)sqrt(p));
    30     exgcd(ksm(a, ps, p), p, x, y);
    31     x = (x % p + p) % p;
    32     mp[1] = 0;
    33     for(int i = 1, t = a; i <= ps; ++i, t = t * a % p) if(!mp[t]) mp[t] = i;//这里要求先输出最先读到的那一天所以要判空 
    34     for(int i = 0, xx = 1; i <= ps; ++i, xx = xx * x % p)
    35     {
    36         if(b * xx % p == 1) return ps * i;//这里由于我前面设了mp[1] = 0所以要特判一下 
    37         if(mp[b * xx % p]) return ps * i + mp[b * xx % p];
    38     }
    39     return -1;
    40 }
    41 int main()
    42 {
    43     scanf("%d", &T);
    44     while(T--)
    45     {
    46         scanf("%lld %lld %lld %lld %lld", &p, &a, &b, &x1, &t);
    47         if(t == x1)//特判 
    48         {
    49             puts("1");
    50             continue;
    51         }
    52         if(a == 0)//特判 
    53         {
    54             if(t == b) puts("2");
    55             else puts("-1");
    56             continue;
    57         }
    58         if(a == 1)//exgcd求 
    59         {
    60             ll c = t + b - x1;
    61             c = (c % p + p) % p;//先取模 
    62             if(!c)//c = 0直接输出p就是了,具体为什么自己把c = 0的式子带进去推 
    63             {
    64                 printf("%lld
    ", p);
    65                 continue;
    66             } 
    67             exgcd(b, p, x, y);
    68             x =    (x % p + p) % p;
    69             if(c % d != 0) puts("-1");
    70             else printf("%lld
    ", (x * c / d % p + p) % p);
    71             continue;
    72         }//bsgs求 
    73         exgcd(((x1 - x1 * a - b) % p + p) % p, p, x, y);
    74         x = (x % p + p) % p;
    75         ll tt = bsgs(a, t * x - t * a % p * x - b * x, p);//三连乘别忘了取模 
    76         if(tt != -1) printf("%lld
    ", tt + 1);
    77         else puts("-1");
    78     }
    79     return 0;
    80 }

     调试代码所用的bat:

    :begin
    maker.exe > P3306.in
    随机数生成器.exe < P3306.in > P3306.out
    brute.exe < P3306.in > P3306.ans
    fc P3306.out P3306.ans
    if not errorlevel = 1 goto begin
    pause

    brute就是上面的暴力,maker就是我自己写的一个数据生成器。

  • 相关阅读:
    java 多线程学习(一)
    解决安卓微信浏览器刷新问题
    sublime text3 配置tab为4个空格
    React 错误Each child in an array or iterator should have a unique “key” prop
    git filename to long问题解决
    JS获取URL参数 方法
    CSS超出2行省略号
    JS判断是否为安卓orIOS
    获取移动设备真实宽高
    微信分享朋友圈监听(PHP)
  • 原文地址:https://www.cnblogs.com/qqq1112/p/13504640.html
Copyright © 2011-2022 走看看