题目链接

题意:

  • 给定\(n,x_0,a,b,p\),有递推式\(x_i = (a \cdot x_{i-1} +b)\%p\)。
  • 有\(Q\)个询问,每次询问给定一个\(v\),问是否存在一个最小的\(i\)使得\(x_i=v,i\in[0,n-1]\)成立
  • \(1\le n\le 1e18,0\le x_p,a,b<p\le 1e9+7,Q\le 1000,p\)是质数

大步小步(BSGS)学习:https://oi-wiki.org/math/bsgs/

刘汝佳白书数论中也有入门讲解

如果直接看递推式找不到关系可以先列出前几项

\(x_0 = x_0\quad x_1=ax_0+b\quad x_2=a^2x_0+ab+b\quad x_3=a^3x_0+a^2b+ab+b\)

\(x_4=a^4x_0+\sum_{i=0}^3a^ib\quad x_5=a^5x_0+\sum_{i=0}^4a^ib\quad x_6=a^6x_0+\sum_{i=0}^5a^ib\quad x_7=a^7x_0+\sum_{i=0}^6a^ib\)

\(\cdots\)

在BSGS中,\(a^x\equiv b\pmod p\)的求解是前求出前\(m\)项(\(m\)通常取\(\sqrt p\))的答案(即\(a^i\%p,i\in[0,m]\)),存在一个数组中便于查询(值和位置一般都要存),然后再从\([m+1,2m]\)中找答案,如果这一层中有答案那么也就是说\(a^{i+m} \equiv b\pmod p,i+m\in [m+1,2m])\)可以发现如果把指数上的\(m\)挪到右边,也就是相当于右侧乘了一个\(a^m\)的逆元,式子变成了\(a^i\equiv b\cdot a^{-m}\pmod p\),所以我们在考虑第二层中是否有答案时,只需要将\(b\)先成一次\(a^m\)的逆元,然后再从我们预处理出来的第一层的答案中寻找是否有解即可。

那么这个题该怎么像上面这个进行一样的操作呢?

我们观察一下,考虑完上一层之后接着考虑下一层的时候,给b乘\(a^m\)的逆元操作意味着什么?该操作可以理解为是除以\(a^m\),也就是将乘了\(m\)次\(a\)的操作复原了。基于复原思想,如何复原到m次操作之前的结果呢?

回看之前列出来的前8项,假设一层有4个,那么复原就相当于是将\(x_4\)变回\(x_0\)。

\[a^4x_0+a^3b+a^2b+ab+b \rightarrow x_0
\]
\[{a^4x_0+a^3b+a^2b+ab+b \over a^4} = x_0+\frac ba +\frac b{a^2}+\frac b{a^3}+\frac b{a^4}
\]

如果还看不出来,在列一下下一个

\[a^5x_0+a^4b+a^3b+a^2b+ab+b \rightarrow ax_0+b
\]
\[{a^5x_0+a^4b+a^3b+a^2b+ab+b \over a^4} = (ax_0+b)+\frac ba +\frac b{a^2}+\frac b{a^3}+\frac b{a^4}
\]

显然,先除以\(a^4\),然后再减去\(\frac ba +\frac b{a^2}+\frac b{a^3}+\frac b{a^4}\)即可。

其他处理就几乎和BSGS入门题一样了。

该题如果每次查询\(O(\sqrt p)\)的话会超时,所以我们通过加大预处理的范围去降低时间复杂度。(更多的部分是可以直接算出来存到数组里面的)采取\(O(\sqrt {Qp})\)也就是1e6的大小。

代码&程序流程梳理

  1. 特判a == 0,如果查询vx0要先输出0,等于b再输出1,否则输出-1(注意一下如果x0b,答案要首先输出0)
  2. 预处理前1e6的答案,存在pair里面之后排序,去重
  3. 计算\(a^{1e6}\)的逆元,还有我们复原需要减去的那一坨东西
  4. 然后从第一层开始找,二分查询位置,如果没找到就找下一层,如果发现现在找的位置大于等于n的话要及时结束查找。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000000;
int T;
ll x0,n,a,b,p;
ll ksm(ll a,ll b){
ll res = 1;
for(;b;b>>=1){
if(b & 1)res = res*a%p;
a = a * a % p;
}
return res;
}
pair<int,int> node[maxn];
int pos[maxn],val[maxn];
int main(){
scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld%lld%lld",&n,&x0,&a,&b,&p);
int Q;scanf("%d",&Q);
if(a == 0){
while(Q--){
int v;scanf("%d",&v);
if(v == x0)
puts("0");
else if(v == b) puts("1");
else puts("-1");
}
continue;
}
ll now = x0;
int up = min(n,(ll)maxn);
for(int i=0;i<up;i++){
node[i] = {now,i};
now = (now * a + b) % p;
}
sort(node,node+up);
int m = 0;
for(int i=0;i<up;i++){
val[m] = node[i].first;
pos[m++] = node[i].second;
while(i < up - 1 && node[i].first == node[i+1].first)i++;
}
int inv_a = ksm(a,p-2);
int inv_b = (p-b)%p*inv_a%p;
ll bb = 0, aa = 1;
for(int i=0;i<maxn;i++){
aa = aa * inv_a % p;
bb = (bb * inv_a + inv_b) % p;
}
int r = p / maxn + 1;
while(Q--){
int v;scanf("%d",&v);
int id = lower_bound(val,val+m,v) - val;
if(id < m && val[id] == v){
printf("%d\n",pos[id]);continue;
}
if(n < maxn){
puts("-1");continue;
}
bool flag = false;
for(int i=1;i<=r;i++){
v = (aa * v + bb) % p;
int id = lower_bound(val,val+m,v) - val;
if(id < m && val[id] == v){
int res = pos[id] + i * maxn;
if(res >= n)puts("-1");
else printf("%d\n",res);
flag = true;break;
}
}
if(!flag)puts("-1");
}
}
return 0;
}

最后提一下,复原的时候也可以先减后乘逆元

那么循环里面bb的更新就变成

ll bb = 0, aa = 1;
for(int i=0;i<maxn;i++){
aa = aa * inv_a % p;
bb = (bb*a%p + b) % p;
}
//循环查找中v的更新
v = (v-bb+p)%p*aa%p;

2019牛客暑期多校训练营(第五场)C - generator 2 (BSGS)的更多相关文章

  1. 2019牛客暑期多校训练营(第五场) maximum clique 1

    题意:给出n个不相同的数,问选出尽量多的数且任两个数字二进制下不同位数大于等于2. 解法:能想到大于等于2反向思考的话,不难发现这是一个二分图,那么根据原图的最大团等于补图的最大独立点集,此问题就变成 ...

  2. 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)

    题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9:  对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可.     后者mod=1e9,5才 ...

  3. 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...

  4. 2019牛客暑期多校训练营(第一场) B Integration (数学)

    链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...

  5. 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)

    链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...

  6. 2019牛客暑期多校训练营(第二场)F.Partition problem

    链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...

  7. 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...

  8. [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem

    链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...

  9. 2019牛客暑期多校训练营(第二场)J-Subarray(思维)

    >传送门< 前言 这题我前前后后看了三遍,每次都是把网上相关的博客和通过代码认真看了再思考,然并卵,最后终于第三遍也就是现在终于看懂了,其实懂了之后发现其实没有那么难,但是的的确确需要思维 ...

  10. 2019牛客暑期多校训练营(第一场)-A (单调栈)

    题目链接:https://ac.nowcoder.com/acm/contest/881/A 题意:给定两个长度均为n的数组a和b,求最大的p使得(a1,ap)和(b1,bp)等价,等价的定义为其任意 ...

随机推荐

  1. RHEL8/CentOS8的网络IP配置

    rhel8与7的区别 在rhel7上,同时支持network.service和NetworkManager.service(简称NM).默认情况下,这2个服务都有开启,但许多人都会将NM禁用掉. 在r ...

  2. java反射-Method中的invoke方法的用法-以及函数式接口和lambda表达式

    作者最近研究框架底层代码过程中感觉自己基础不太牢固,于是写了一点案例,以防日后忘记 接口类:Animals 1 public interface Animals { 2 3 public void e ...

  3. ArrayDeque API 与算法分析

    ArrayDeque 是双端队列的动态数组实现,可以当作栈和队列来使用.作为栈时,它的效率比 Stack 更高,作为队列时,效率比 LinkedList 更高.ArrayDeque 大部分操作的时间复 ...

  4. Unity优化 1

    浅谈Unity中的GC以及优化(转) Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译文搬运了过来,作为上面思 ...

  5. 剑指offer之重建二叉树

    1.问题描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.        例如输入前序遍历序列pre {1,2,4,7,3,5,6, ...

  6. MongoDB导出导入功能

    导出脚本: mongo_export.sh !#/bin/bash mongoexport -h x.x.x.x  --port 27017 -d database -c collection  -q ...

  7. zabbix的汉化

    1.在windows中找一个自己喜欢的字体(C:\Windows\Fonts)或者去网上下载一个 2.将字体上传到zabbix的web相关目录的fonts目录下 (我的zabbix的web相关的文件都 ...

  8. 【数据结构与算法】Java制作一个简单数组类

    bobo老师的玩转算法系列–玩转数据结构 简单记录 文章目录 不要小瞧数组 - 制作一个数组类 1 .使用Java中的数组 数组基础 简单使用 2.二次封装属于我们自己的数组 数组基础 制作属于我们自 ...

  9. ctfhub技能树—信息泄露—git泄露—index

    打开靶机 查看页面信息 使用dirsearch进行扫描 使用githack工具处理git泄露情况 使用git log命令查看历史记录 与 add flag 9b5b58-- 这次提交进行比对 即可拿到 ...

  10. printf函数输出格式总结

    printf函数格式 函数描述: printf("[格式化字符串]", [参数链表]); 函数声明: int printf(const char *format, ...) ; 输 ...