【51nod】1123 X^A Mod B (任意模数的K次剩余)
题解
K次剩余终极版!orz
写一下,WA一年,bug不花一分钱
在很久以前,我还认为,数论是一个重在思维,代码很短的东西
后来。。。我学了BSGS,学了EXBSGS,学了模质数的K次剩余……代码一个比一个长……
直到今天,我写了240行的数论代码,我才发现数论这个东西= =太可怕了
好吧那么我们来说一下任意模数的K次剩余怎么搞
首先,如果模数是奇数,我们可以拆成很多个质数的指数幂,再用解同余方程的方法一个个合起来,细节之后探讨
但是如果,模数有偶数呢
因为要输出所有解,解的个数不多,我们可以倍增,也就是如果模数有一个\(2^k\)因子,那么它在模\(2^{k - 1}\)情况下的所有解x,如果还要在\(2^{k}\)成立,必定是\(x\)或\(x + 2^{k - 1}\)
我们对于每一个检查一下就好了
这样,我们就只要考虑模奇数的情况了
对于一个质数的指数幂\(p^{k}\) 有\(x^{A} \equiv C \pmod {p^{k}}\)
若\(C == 0\)
那么\(x\)中必然有\(p^{\lceil \frac{k}{A} \rceil}\)这个因子,之后从0枚举,一个个乘起来就是\(x\)可能的取值
若\(C \% p == 0\)
也就是说,\(C\)可以写成\(u * p^{e}\)的形式,有解必定有\(A|e\)
那么就是\(x^{A} \equiv u * p^{e} \pmod {p^{k}}\)
把同余式打开,可以有\(x^{A} = u * p^{e} + h * p^{k}\)
等式两边都除掉一个\(p^{e}\)就有
\((\frac{x}{p^{\frac{e}{A}}})^{A} = u + h * p^{k - e}\)
设\(t = \frac{x}{p^{\frac{e}{A}}}\)
我们要求的就是
\(t^{A} \equiv u \pmod {p^{k - e}}\)
这时候\(u\)必然和模数互质,可以套用模质数的K次剩余
此时求出来的指标要取模的数是\(\phi(p^{k - e})\)而不是\(\phi(p^k)\)
之后求出所有指标的上界是\(\phi(p^k)\) (就是不断增加\(\frac{\phi(p^{k - e})}{gcd(\phi(p^{k - e},A))}\)的时候)
如果\(C\)和\(p\)互质
那么直接上模质数的K次剩余(虽然是质数的指数幂但是你不需要用到有质数的那些位置了)
最后求完了,和上一次的答案用同余方程合起来即可
(附赠51nod上tangjz的hack数据,我虽然ac了然而这个hack没过,又调了一段时间才过掉)
输入
1
3 531441 330750
输出
264 19947 39630 59313 78996 98679 118362 138045 157728 177411 197094 216777 236460 256143 275826 295509 315192 334875 354558 374241 393924 413607 433290 452973 472656 492339 512022
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
//#define ivorysi
#define MAXN 100005
#define eps 1e-7
#define mo 974711
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
int64 A,B,C,G,eu;
int64 ans[MAXN],tmp[MAXN],R,L[MAXN],cntL;
int M;
struct node {
int next,num;
int64 hsh;
}E[MAXN];
int head[mo + 5],sumE;
int64 fpow(int64 x,int64 c,int64 MOD) {
int64 res = 1,t = x;
while(c) {
if(c & 1) res = res * t % MOD;
t = t * t % MOD;
c >>= 1;
}
return res;
}
int primitive_root(int64 P,int64 eu) {
static int64 factor[1005];
int cnt = 0;
int64 x = eu;
for(int64 i = 2 ; i <= x / i ; ++i) {
if(x % i == 0) {
factor[++cnt] = i;
while(x % i == 0) x /= i;
}
}
if(x > 1) factor[++cnt] = x;
for(int G = 2 ; ; ++G) {
for(int j = 1 ; j <= cnt ; ++j) {
if(fpow(G,eu / factor[j],P) == 1) goto fail;
}
return G;
fail:;
}
}
int64 gcd(int64 a,int64 b) {
return b == 0 ? a : gcd(b,a % b);
}
void ex_gcd(int64 a,int64 b,int64 &x,int64 &y) {
if(b == 0) {
x = 1,y = 0;
}
else {
ex_gcd(b,a % b,y,x);
y -= a / b * x;
}
}
int64 Inv(int64 num,int64 MOD) {
int64 x,y;
ex_gcd(num,MOD,x,y);
x %= MOD;x += MOD;
return x % MOD;
}
void add(int u,int64 val,int num) {
E[++sumE].hsh = val;
E[sumE].next = head[u];
E[sumE].num = num;
head[u] = sumE;
}
void Insert(int64 val,int num) {
int u = val % mo;
for(int i = head[u] ; i ; i = E[i].next) {
if(val == E[i].hsh) {
E[i].num = num;
return;
}
}
add(u,val,num);
}
int Query(int64 val) {
int u = val % mo;
for(int i = head[u] ; i ; i = E[i].next) {
if(val == E[i].hsh) {
return E[i].num;
}
}
return -1;
}
int BSGS(int64 A,int64 C,int64 P) {
memset(head,0,sizeof(head));sumE = 0;
int64 S = sqrt(P);
int64 t = 1,invt = 1,invA = Inv(A,P);
for(int i = 0 ; i < S ; ++i) {
if(t == C) return i;
Insert(invt * C % P,i);
t = t * A % P;
invt = invt * invA % P;
}
int64 tmp = t;
for(int i = 1 ; i * S < P ; ++i) {
int x = Query(tmp);
if(x != -1) {
return i * S + x;
}
tmp = tmp * t % P;
}
}
bool Process(int64 A,int64 C,int64 P,int k) {
int64 MOD = 1,g;
for(int i = 1 ; i <= k ; ++i) MOD *= P;
cntL = 0;
if(C % MOD == 0) {
int64 T = (k - 1) / A + 1;
L[++cntL] = 0;
if(T < k) {
int64 num = fpow(P,T,MOD);
for(int i = 1 ; i * num < MOD ; ++i) L[++cntL] = i * num;
}
}
else if(g = gcd(C % MOD,MOD) != 1){
int64 x = C % MOD;
int c = 0;
while(x % P == 0) ++c,x /= P;
if(c % A != 0) return false;
G = primitive_root(MOD / (C / x),eu / (C / x));
eu /= C / x;
int e = BSGS(G,x,MOD / (C / x));
g = gcd(A,eu);
if(e % g != 0) return false;
e /= g;
int64 s = Inv(A / g,eu / g) * e % (eu / g);
L[++cntL] = s;
while(1) {
if((L[cntL] + eu / g) % (eu * (C / x)) == L[1]) break;
L[cntL + 1] = L[cntL] + eu / g;
++cntL;
}
for(int i = 1 ; i <= cntL ; ++i) {
L[i] = fpow(G,L[i],MOD) * fpow(P,c / A,MOD) % MOD;
}
}
else {
int e = BSGS(G,C % MOD,MOD);
g = gcd(A,eu);
if(e % g != 0) return false;e /= g;
int s = Inv(A / g,eu / g) * e % (eu / g);
L[++cntL] = s;
while(1) {
if(L[cntL] + eu / g >= eu) break;
L[cntL + 1] = L[cntL] + eu / g;
++cntL;
}
for(int i = 1 ; i <= cntL ; ++i) L[i] = fpow(G,L[i],MOD);
}
if(!cntL) return false;
if(!M) {
M = cntL;
for(int i = 1 ; i <= M ; ++i) ans[i] = L[i];
sort(ans + 1,ans + M + 1);
M = unique(ans + 1,ans + M + 1) - ans - 1;
R = MOD;
return true;
}
int tot = 0;
for(int i = 1 ; i <= M ; ++i) {
for(int j = 1 ; j <= cntL ; ++j) {
tmp[++tot] = (R * Inv(R,MOD) % (R * MOD) * (L[j] - ans[i]) + ans[i]) % (R * MOD);
tmp[tot] = (tmp[tot] + R * MOD) % (R * MOD);
}
}
R *= MOD;
sort(tmp + 1,tmp + tot + 1);
tot = unique(tmp + 1,tmp + tot + 1) - tmp - 1;
for(int i = 1 ; i <= tot ; ++i) ans[i] = tmp[i];
M = tot;
return true;
}
void Solve() {
M = 0;
if(B % 2 == 0) {
int64 Now = 2;B /= 2;
if(C & 1) ans[++M] = 1;
else ans[++M] = 0;
while(B % 2 == 0) {
B /= 2;
Now *= 2;
int t = 0;
for(int i = 1 ; i <= M ;++i) {
if(fpow(ans[i],A,Now) == C % Now) tmp[++t] = ans[i];
if(fpow(ans[i] + Now / 2,A,Now) == C % Now) tmp[++t] = ans[i] + Now / 2;
}
for(int i = 1 ; i <= t ; ++i) ans[i] = tmp[i];
if(!t) goto fail;
M = t;
}
R = Now;
sort(ans + 1,ans + M + 1);
M = unique(ans + 1,ans + M + 1) - ans - 1;
}
for(int64 i = 3 ; i <= B / i ; ++i) {
if(B % i == 0) {
eu = (i - 1);
B /= i;
int num = i,cnt = 1;
while(B % i == 0) {
B /= i;eu *= i;num *= i;++cnt;
}
G = primitive_root(num,eu);
if(!Process(A,C,i,cnt)) goto fail;
}
}
if(B > 1) {
eu = B - 1;
G = primitive_root(B,eu);
if(!Process(A,C,B,1)) goto fail;
}
if(M == 0) goto fail;
sort(ans + 1,ans + M + 1);
for(int i = 1 ; i <= M ; ++i) {
printf("%d%c",ans[i]," \n"[i == M]);
}
return;
fail:
puts("No Solution");
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T;
scanf("%d",&T);
while(T--) {
scanf("%lld%lld%lld",&A,&B,&C);
Solve();
}
}
【51nod】1123 X^A Mod B (任意模数的K次剩余)的更多相关文章
- 51NOD 1258 序列求和 V4 [任意模数fft 多项式求逆元 伯努利数]
1258 序列求和 V4 题意:求\(S_m(n) = \sum_{i=1}^n i^m \mod 10^9+7\),多组数据,\(T \le 500, n \le 10^{18}, k \le 50 ...
- 51nod 1172 Partial Sums V2 卡精度的任意模数FFT
卡精度的任意模数fft模板题……这道题随便写个表就能看出规律来(或者说考虑一下实际意义),反正拿到这题之后,很快就会发现他是任意模数fft模板题.然后我就去网上抄了一下板子……我打的是最土的任意模数f ...
- [洛谷P4245]【模板】任意模数NTT
题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...
- 拆系数FFT(任意模数FFT)
拆系数FFT 对于任意模数 \(mod\) 设\(m=\sqrt {mod}\) 把多项式\(A(x)\)和\(B(x)\)的系数都拆成\(a\times m+b\)的形式,时\(a, b\)都小于\ ...
- 【模板】任意模数NTT
题目描述: luogu 题解: 用$fft$水过(什么$ntt$我不知道). 众所周知,$fft$精度低,$ntt$处理范围小. 所以就有了任意模数ntt神奇$fft$! 意思是这样的.比如我要算$F ...
- 【知识总结】多项式全家桶(三)(任意模数NTT)
经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...
- 任意模数FFT
任意模数FFT 这是一个神奇的魔法,但是和往常一样,在这之前,先 \(\texttt{orz}\ \color{orange}{\texttt{matthew99}}\) 问题描述 给定 2 个多项式 ...
- MTT:任意模数NTT
MTT:任意模数NTT 概述 有时我们用FFT处理的数据很大,而模数可以分解为\(a\cdot 2^k+1\)的形式.次数用FFT精度不够,用NTT又找不到足够大的模数,于是MTT就应运而生了. MT ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
随机推荐
- tf.nn.conv2d 参数介绍
tf.nn.conv2d是TensorFlow里面实现卷积的函数,参考文档对它的介绍并不是很详细,实际上这是搭建卷积神经网络比较核心的一个方法,非常重要 tf.nn.conv2d(input, fil ...
- Java基础-进程与线程之Thread类详解
Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...
- [LeetCode] 398. Random Pick Index ☆☆☆
Given an array of integers with possible duplicates, randomly output the index of a given target num ...
- ZeroMQ API(二) 上下文
1.创建上下文 1.1 zmq_ctx_new(3) 1.1.1 名称 zmq_ctx_new - 创建新的ZMQ上下文 1.1.2 概要 void * zmq_ctx_new(); 1.1.3 描述 ...
- 解析html与xhtml的神器——HTMLParser与SGMLParser
有时候你要把抓回来的数据进行提取,过大篇幅的html标签,你若使用正则表达式进行匹配的话,显然是低效的,这时使用python的HTMLParser模块会显得非常方便.据说还有个比较好用的解析器叫:Be ...
- UNIX环境高级编程 第2章 UNIX标准及实现
在过去的将近25年时间,人们为了UNIX的标准化做出了种种努力,这使得程序在不同版本的UNIX系统之间的移植相当容易. ISO C 1989年,C语言首个标准得到批准,其为C89.次年,一个带有小改动 ...
- 初涉sqlmap
1.基本注入(这个工具kali或者bt下面有集成的,这里附加一个window免py版,提取码:3ldv) sqlmap -u http://url/xx.php?id=1 判断注入 sqlmap - ...
- Spring4笔记6--Spring与AOP
Spring与AOP: AOP的引入: 主业务经常需要调用系统级业务(交叉业务),如果在主业务代码中大量的调用系统级业务代码,会使系统级业务与主业务深度耦合在一起,大大影响了主业务逻辑的可读性,降低了 ...
- Struts2笔记1:--Struts2原理、优点、编程流程、6大配置文件以及核心配置文件struts.xml
Struts2原理(底层使用的是Servlet的doFilter方法): Struts2优点: 第一个Struts程序: 在开发Struts程序之前,首先要导入额外的jar包,基本需求的是14个jar ...
- ubuntu16.04 源码方法安装tensorflow
参考博客:http://blog.csdn.net/zhaoyu106/article/details/52793183/,http://blog.csdn.net/u010900574/articl ...