【快速筛可能是大费马素数的数】
2015-07-24 00:37
453 查看
为什么写这样一篇博客呢……,原因是今天的多校有道题用到了NTT,然后用双模数然后中国剩余定理我被卡到死,直到我中间运算数组换成了int才卡过。之后我发现,竟然有一个O(1)的大数快速乘法(进行运算的数都在long long内)。根据这个,我发现NTT完全可以通过寻找一个超级大的费马素数来实现(比运算后的系数还大~),代替双模数的中国剩余定理的NTT写法,因为这个常数太大了……
通过我无聊到极点的耐心,我把这个方法写的更加无脑了,鉴于本人低能,以及方便的前提下,只枚举2的幂次,以及另外的两个素数,代码如下,就是纯暴力~
这样随便选一组可行的费马素数,就可以了……前提是这一组确实是素数,233……
my code:my~~code:
通过我无聊到极点的耐心,我把这个方法写的更加无脑了,鉴于本人低能,以及方便的前提下,只枚举2的幂次,以及另外的两个素数,代码如下,就是纯暴力~
这样随便选一组可行的费马素数,就可以了……前提是这一组确实是素数,233……
my code:my~~code:
[code]#include <bits/stdc++.h> using namespace std ; typedef long long LL ; typedef unsigned long long ULL ; const int MAXN = 5005 ; LL mod ; ULL L_bound = 3e18 , R_bound = 4.5e18 ;//筛取费马素数的上下界 bool prime[MAXN] ; LL mul ( LL x , LL y ) {//O(1)快速乘法,进行运算的数都在long long内 return ( x * y - ( long long ) ( x / ( long double ) mod * y + 1e-3 ) * mod + mod ) % mod ; } LL power ( LL a , LL b ) {//快速幂 LL res = 1 , tmp = a ; while ( b ) { if ( b & 1 ) res = mul ( res , tmp ) ; tmp = mul ( tmp , tmp ) ; b >>= 1 ; } return res ; } void preprocess () {//预处理素数 memset ( prime , 1 , sizeof prime ) ; prime[0] = prime[1] = 0 ; for ( LL i = 2 ; i < MAXN ; ++ i ) if ( prime[i] ) { for ( LL j = i * i ; j < MAXN ; j += i ) prime[j] = 0 ; } } int main () { int cas = 0 ; preprocess () ; for ( LL P0 = 23 ; ( 1LL << P0 ) <= R_bound ; ++ P0 ) if ( prime[P0] ) { ULL tmp = ( 1LL << P0 ) ; for ( LL P1 = 3 ; tmp * P1 <= R_bound && P1 < MAXN ; ++ P1 ) if ( prime[P1] ) { for ( LL P2 = 3 ; tmp * P1 * P2 <= R_bound && P2 < MAXN ; ++ P2 ) if ( P2 > P1 && prime[P2] ) { mod = ( 1LL << P0 ) * P1 * P2 + 1 ; if ( mod < L_bound ) continue ; LL t = mod - 1 ; LL x0 = t / 2 ; LL x1 = t / P1 ; LL x2 = t / P2 ; int ok = 0 ; for ( LL i = 1 ; i <= 10 ; ++ i ) { if ( power ( i , x0 ) != 1LL && power ( i , x1 ) != 1LL && power ( i , x2 ) != 1LL ) { if ( i != 2 ) { /* 原根得到是2的基本可以确定是非素数…… 而不是2的应该大部分都是素数吧…… 我猜的…… 这个可以人工验算,或者去套用Miller_Rabbin(米勒-拉宾)算法判断下就好…… */ LL tmp = mod , x = 0 ; for ( ; tmp ; ++ x , tmp /= 10 ) ; printf ( "Case #%d:\n" , ++ cas ) ; printf ( "P0 = %I64d , P1 = %I64d , P2 = %I64d\n" , P0 , P1 , P2 ) ; printf ( "mod = %I64d , g = %I64d\n" , mod , i ) ; printf ( "%I64d\n\n" , x ) ; ok = 1 ; } break ; } if ( ok ) break ; } } } } return 0 ; }
相关文章推荐
- Codeforces Round #313 (Div. 2) E. Gerald and Giant Chess 定理Lucas求大组合数
- 不规则混排实现(实现图文环绕的效果)
- Delph i2010
- mysql给数据库表里某个字段赋随机值
- [嵌入式Linux驱动]S5PV210的烟雾传感器Linux驱动
- hdu5308 I Wanna Become A 24-Point Master 含 spj
- JavaScript 中的相等检测
- 黑马程序员——学习一维数组的地址
- EularProject 48: 利用数组求和
- C++11新特性
- ubuntu 12.04下编译安装nginx-1.9.3之后 tomcat集群
- 设计模式
- IOS UIPanGestureRecognizer手势使用及识别状态UIGestureRecognizerState
- JDBC快速入门
- nodejs学习笔记一
- 简单的字谜游戏--可扩展--2015年7月25日14:58:00V1.1版
- 【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记38 Unwind Segue反向过渡
- 常见邮件服务器
- Objective-C 学习笔记一
- 比对的一个工具类