暑假集训 || 初等数论
·中国剩余定理
·扩展中国剩余定理
·莫比乌斯反演
模板:
void Moblus() { memset(check,false,sizeof(check)); mu[1] = 1; int tot = 0; for(int i = 2; i <= MMX; i++) { if( !check[i] ) { prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot; j++) { if(i * prime[j] > MMX) break; check[i * prime[j]] = true; if( i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } else { mu[i * prime[j]] = -mu[i]; } } } }
HDU 1695
题意:给abcd,a==1, c==1, 求[a, b]中的x 和[c, d]中的y, 是的gcd(x, y) == k,问有多少对这样的x和y,(5, 3)和(3, 5)算一对
思路:https://blog.csdn.net/lixuepeng_001/article/details/50577932 这里讲的比较详细。。好难QAQ
注意k可能为0,为0的时候时候也要输出case
然后乘的时候会爆int,不如全改成LL哇
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const LL SZ = 100100; bool check[SZ]; LL mu[SZ], prime[SZ]; void Moblus() { memset(check,false,sizeof(check)); mu[1] = 1; LL tot = 0; for(LL i = 2; i <= 100050; i++) { if(!check[i]) { prime[tot++] = i; mu[i] = -1; } for(LL j = 0; j < tot; j++) { if(i * prime[j] > 100050) break; check[i * prime[j]] = true; if( i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } else { mu[i * prime[j]] = -mu[i]; } } } } int main() { int T, tt = 0; scanf("%d", &T); Moblus(); while(T--) { LL a, b, c, d, k; scanf("%lld %lld %lld %lld %lld", &a, &b, &c, &d, &k); if(k == 0) { printf("Case %d: 0\n", ++tt); continue; } b /= k, d /= k; if(b > d) swap(b, d);//b <= d LL ans = 0, add = 0; for(LL i = 1; i <= b; i++) ans += (b / i) * (d / i) * mu[i]); for(LL i = 1; i <= b; i++) add += (b / i) * (b / i) * mu[i]); printf("Case %d: %lld\n", ++tt, ans - add/2); } return 0; }
·法雷级数
就是这个东东
中间每一个数的分子都是它左右两数分子之和,分母也是
用途:分数逼近,类似二分
HDU 6290
题意:给一个无理数,求出分母在1e5以内的最接近它的最简分数
思路:法雷级数里面能表示所有最简的真分数,用类似二分的方法不断逼近,取两个数中间的分数看要求的无理数在它的左边还是右边
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; typedef long double LD; const int SZ = 1000100; const int eps = 1e-9; int main() { int T; scanf("%d", &T); while(T--) { int k; scanf("%d", &k); LD dk = pow((LD)k, (LD)2.0/3.0); LL tmp = floor(dk); dk -= tmp; LL a1 = 0, a2 = 1, b1 = 1, b2 = 1; while(b1+b2 <= 100000LL) { LL mida = a1+a2, midb = b1+b2; LD ans = (LD)mida / midb; if(ans < dk) a1 = mida, b1 = midb; else a2 = mida, b2 = midb; } LD ans1 = (LD)a1 / b1, ans2 = (LD)a2 / b2; if(dk - ans1 < ans2 - dk) printf("%lld/%lld\n", a1 + tmp * b1, b1); else printf("%lld/%lld\n", a2 + tmp * b2, b2); } return 0; }
·指数循环节
·Lucas定理
·BM算法