隱藏在素數規律中的Pi -- BZOJ1041解題報告
退役狗在刷程書的過程中看到了一個有趣的視頻, 講解了一個有趣的問題.
在網上隨便搜索了一下居然還真的找到了一道以它爲背景的OI題目, BZOJ1041.
下面的內容會首先回顧一下視頻所討論的知識, 有了這些知識, 自然就明白應該怎麼去做這道題了.
另外, 這道題在網路上的解法大多是暴力求解, 這篇博客也提出了本題一個複雜度爲\(\mathcal{O}(分解質因數)\)的解決方案.
隱藏在素數規律中的\(\pi\)
首先介紹收斂於\(\pi\)的一個無窮級數:
\]
怎麼證明它呢? 一種常見方法是使用Calculus, 另外一種就是使用數論方法.
Consider有一個網格, 我們畫出一個半徑爲\(r\)的圓:
\]
那麼, 如果我們能夠數出來這裏面有多少個點, 我們就可以間接計算出\(pi\)的值.
我們把這個圓分成若干個小圓, 假設每個圓的方程是:
\]
我們可以枚舉所有可能的\(n\)來確定圓中有多少個格點.
考慮到格點的\(x, y\)都是integer, 那麼我們只需要去枚舉所有小於\(r^2\)的整數\(n\)就可以了.
那麼現在問題就轉化成:
給定一個正整數\(n\), 有多少個pair\((x, y)\)使得\(x^2+y^2=n\)成立?
考察\(n\)的任意一個分解\(n = x^2+y^2\), 若存在這樣一個分解, 這樣的分解也可以寫成:
\]
考慮\(n\)的質因數分解:
\(n = \prod p_i^{a_i}\)
對於其中的一個素數, 我們不加證明地給出幾個結論:
- \(p_i\)能夠被共軛分解的衝要條件是\(p_i\equiv1 \mod 4\), 或者\(p_i = 2\).
- 上面的分解被視爲"Almost Unique"的, 因爲如果我們對於一個分解中的偶數個因子都乘以\(1, -1, i, -i\), 那麼新的分解仍然是成立的.
然後, 我們可以對幾種因子作分類討論:
- \(p_i \mod 4 = 1\)
若出現這樣的情形, 在不考慮乘以\(1, -1, i, -i\)的情況下, 我們可以將這分解出來的\(2a_i\)個複數隨意組合相乘, 可以證明得到的兩個共軛複數不同的情形有\(a_i+1\)種.
- \(p_i \mod 4 = 3\)
這樣的素數叫做高斯素數. 若出現這樣的情形, 如果\(a_i\)是偶數, 我們可以在之前得到了的兩個共軛複數上都乘以\(p_i^{a_i/2}\)而不影響結果. 否則, 方案數就是0.
- \(p_i = 2\)
若出現這樣的情形, 理論上來說2可以分解成\(2 = (1+i)(1-i)\), 但是有\((1-i)*i = (1+i)\), 從而不管怎麼分組, 都會與最終的乘以\(1, -1, i, -i\)相重複, 所以對於方案數目的貢獻只有\(\times 1\)
經過上面的討論, 我們就得到了計數拆分\(n = x^2+y^2\)方案的一個方法. 具體的方案與代碼在下面的題解中給出.
到現在, 這個結果已經蠻不錯, 但是我們還可以做的更優美.
定義函數:
\begin{cases}
1, &x \mod 4 = 1\cr 0, &x \mod 2 = 0 \cr -1, &x \mod 4 = 3\end{cases}
\end{eqnarray}
\]
這個函數是一個積性函數.
通過\(\chi(x)\)定義中的分類討論, 在求解的時候, 我們便不必再分類討論了.
這樣, 我們要求得的答案就可以寫成:
\]
考慮到上述函數是一個積性函數, 我們有:
\]
對上述函數稍作整理, 並令\(\lim_{n \rightarrow \infty}\)近似, 就得到了要證的式子.
\]
回到本題
本題是一個上面結論的退化形式, 令\(n = r^2\), 直接應用算法即可.
下面是代碼.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll xjb=10;
ll mmul(ll a, ll b, ll m){
ll d=((long double)a/m*b+1e-8);
ll r=a*b-d*m;
return r<0?r+m:r;
}
ll mpow(ll a, ll b, ll m){ll r=1;for(;b;b>>=1,a=mmul(a,a,m))if(b&1)r=mmul(r,a,m);return r;}
ll gcd(ll a, ll b){return a?gcd(b%a,a):b;}
ll prime(ll n){
if(n==1) return 0;
if(n==2||n==3||n==5) return 1;
if(!(n&1)||(n%3==0)||(n%5==0)) return 0;
ll m=n-1; ll k=0;
while(!(m&1)) m>>=1, k++;
for(ll tt=0; tt<xjb; ++tt){
ll x=mpow(rand()%(n-2)+2,m,n), y=x;
for(ll i=0; i<k; ++i){
x=mmul(x,x,n);
if(x==1&&y!=1&&y!=n-1) return 0;
y=x;
}
if(x!=1) return 0;
}
return 1;
}
ll f[105]; ll M;
ll rho(ll n, ll c){
ll x=rand()%n, y=x, t=1;
for(ll i=1, k=2; t==1; ++i){
x=(mmul(x,x,n)+c)%n;
t=gcd(x>y?x-y:y-x, n);
if(i==k) y=x, k<<=1;
}
return t;
}
void work(ll n){
if(n==1) return;
if(prime(n)){f[M++]=n; return;}
ll t=n;
while(t==n) t=rho(n, rand()%5+1);
work(t); work(n/t);
}
int main(){
srand(19260817);
ll n;
scanf("%lld", &n);
n*=n;
M=0;
work(n);
sort(f, f+M);
ll ans = 1;
for(ll i=0, c=1; i<M; ++i){
if(f[i]!=f[i+1]) {
// cout << f[i] << ' ' << c << endl;
if(f[i] == 2) { }
else if(f[i] % 4 == 1) {
ans *= c+1;
} else {
if(c % 2 == 1) ans = 0;
}
c = 1;
}
else c++;
}
printf("%lld\n", ans*4);
return 0;
}
退役老年選手碼力下降太多了啊....告別OI以後AC的第一道題...感覺還是OI比較美好啊...可惜再也回不去了.
樸素的根號分解過不去這個題, 從網上找了一個Pollard-Rho模板改了改AC了這個題.
又頹廢了一個下午....還有100天就高考了....這樣下去是要gg啊...
隱藏在素數規律中的Pi -- BZOJ1041解題報告的更多相关文章
- BZOJ1002輪狀病毒 暴搜 + 找規律 + 高精度
@[暴搜, 找規律, 高精度] Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个\(n\)轮状基由圆环上\(n\)个不同的基原子和圆心处一个核原子构成的,2个 ...
- 51nod1093(推公式&找規律)
題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1093 題意:中文題誒- 思路:xjb 一開始死活想不出怎麼將一 ...
- oracle系統表、數據字典介紹與日常問題診斷
oracle系統表.數據字典介紹與日常問題診斷 數據字典是由唯讀的table和view組成的,產生於$oracle_home\rdbms\admin\catalog.sql.裡面儲存Oracle資料庫 ...
- php中关于引用(&)详解
php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
- AngularJS select中ngOptions用法详解
AngularJS select中ngOptions用法详解 一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...
- 【转载】C/C++中extern关键字详解
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
- oracle中imp命令详解 .
转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...
- Android中Service(服务)详解
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
随机推荐
- // 关闭调试模式 define('APP_DEBUG', false);
调试模式的优势在于: 开启日志记录,任何错误信息和调试信息都会详细记录,便于调试: 关闭模板缓存,模板修改可以即时生效: 记录SQL日志,方便分析SQL: 关闭字段缓存,数据表字段修改不受缓存影响: ...
- 使用SQLQuery 在Hibernate中使用sql语句
对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口.下面来描述如何使用这个API进行查询. 1.标量查询(Scalar q ...
- MySQL浅谈 LEFT JOIN
On条件(在“A left join b on conditional_expr”)决定如何从table B 中检索数据行(Matching-State); 如果B中没有行匹配On 条件,额外的B的所 ...
- Spring学习之路一
Spring 官网:http://projects.spring.io/spring-framework/ Spring下载地址:https://repo.spring.io/simple/libs- ...
- struts学习总结
-- struts2 是在struts1和webwork基础上发展的全新框架. -- struts2解决的问题: 原始的servlet中,每需要操作一个crud的操作就要创建一个servlet,虽然后 ...
- P1345 [USACO5.4]奶牛的电信Telecowmunication
P1345 [USACO5.4]奶牛的电信Telecowmunication 题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮 ...
- apache日志管理【转】
web服务器日志轮循比较好的方式有三种:第一种方法是利用Linux系统自身的日志文件轮循机制:logrotate:第二种方法是利用apache自带的日志轮循程序rotatelogs:第三种是使用在ap ...
- Java 中的变量
变量 Java 程序的变量大体可分为成员变量和局部变量. 局部变量 形参:在方法签名中定义的局部变量,由方法调用者负责为其赋值,随方法的结束而消亡. 方法内的局部变量:在方法内定义的局部变量,必须在方 ...
- python3 第三章 - 程序的基本结构
1.编码 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串. 当然你也可以为源码文件指定不同的编码: # -*- coding: cp-1252 -* ...
- python_如何对字典进行排序?
案例: 某班英语成绩以字典的形式存储为: {'lili':78, 'jin':50, 'liming': 30, ......} 依据成绩高低,进行学生成绩排名 如何对字典排序? 方法1: #!/us ...