题解

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次剩余)的更多相关文章

  1. 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 ...

  2. 51nod 1172 Partial Sums V2 卡精度的任意模数FFT

    卡精度的任意模数fft模板题……这道题随便写个表就能看出规律来(或者说考虑一下实际意义),反正拿到这题之后,很快就会发现他是任意模数fft模板题.然后我就去网上抄了一下板子……我打的是最土的任意模数f ...

  3. [洛谷P4245]【模板】任意模数NTT

    题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...

  4. 拆系数FFT(任意模数FFT)

    拆系数FFT 对于任意模数 \(mod\) 设\(m=\sqrt {mod}\) 把多项式\(A(x)\)和\(B(x)\)的系数都拆成\(a\times m+b\)的形式,时\(a, b\)都小于\ ...

  5. 【模板】任意模数NTT

    题目描述: luogu 题解: 用$fft$水过(什么$ntt$我不知道). 众所周知,$fft$精度低,$ntt$处理范围小. 所以就有了任意模数ntt神奇$fft$! 意思是这样的.比如我要算$F ...

  6. 【知识总结】多项式全家桶(三)(任意模数NTT)

    经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...

  7. 任意模数FFT

    任意模数FFT 这是一个神奇的魔法,但是和往常一样,在这之前,先 \(\texttt{orz}\ \color{orange}{\texttt{matthew99}}\) 问题描述 给定 2 个多项式 ...

  8. MTT:任意模数NTT

    MTT:任意模数NTT 概述 有时我们用FFT处理的数据很大,而模数可以分解为\(a\cdot 2^k+1\)的形式.次数用FFT精度不够,用NTT又找不到足够大的模数,于是MTT就应运而生了. MT ...

  9. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

随机推荐

  1. html5 +css3 点击后水波纹扩散效果 兼容移动端

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. css选择器 nth-child

    html代码: <div> <p>多云转晴</p> <p>多云转晴</p> <p>多云转晴</p> <p> ...

  3. bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...

  4. 用Python来进行词频统计

    # 把语料中的单词全部抽取出来, 转成小写, 并且去除单词中间的特殊符号 def words(text): return re.findall('[a-z]+', text.lower()) def ...

  5. shell的父子进程

    2017年1月11日, 星期三 shell的父子进程   启动/执行方式: 当前shell:               #!/bin/bash 必须行首                        ...

  6. Redis学习十:Redis的复制(Master/Slave)【重要】

    一.是什么 官网 行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主 二.能干嘛 读写分离  容灾恢 ...

  7. onchange/onpropertychange/oninput

    onpropertychange事件,顾名思义,就是property(属性)change(改变)的时候,触发事件.这是IE专有的!如果想兼容其它浏览器,有个类似的事件,oninput! 可能大家会想到 ...

  8. 图片压缩-KMeans

    下面给大家一起分享使用KMeans自动聚类,压缩图片像素点.每种图片可能他们的维度都不同,比如jpg一共有(w,h,3)三维,但是灰度图只有一维(w,h,1),也有四维的图片(w,h,4)等等.我们可 ...

  9. 在JS数组指定位置插入元素

    很多与数组有关的任务听起来很简单,但实际情况并不总是如此,而开发人员在很多时候也用不到他.最近我碰到了这样一个需求: 将一个元素插入到现有数组的特定索引处.听起来很容易和常见,但需要一点时间来研究它. ...

  10. 推荐一本springBoot学习书籍---深入浅出springBoot2.x

    花了几周时间读完了这本书,确实是一本特别详细全面的书,而且不单单只是springBoot, 书中还介绍了许多工作中常用的技术与springBoot的整合使用,当然,也有一些小bug, 因为在代码实践过 ...