// 2019年西电暑期集训

// [7月9日]基础数论:https://cn.vjudge.net/contest/309097

A - Visible Lattice Points

题目大意:

平面上有N*N个格点,问从原点(0,0)能够看到多少个不被遮挡的点。

数据范围:1<=N<=1000,测试组数:1<=C<=1000。

分析及代码:

暴力计算复杂度N*N*C,肯定T。看题目所给几组样例,也没有发现有什么规律。

注意到点的分布的对称性,对于每一列(x=xi),记录在直线y=x以下能看到的点的坐标:

(1,1)

(2,1)

(3,1),(3,2)

(4,1),(4,3)

(5,1),(5,2),(5,3),(5,4)

......

可以发现直线x=xi上的点的个数为与xi互质的个数,即欧拉函数值phi(xi)。

由对称性,(1,1)重复计算,加上点(1,0)与(0,1),所以本题答案为2*∑phi(xi) + 1。

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. const int maxn = ;
  6. int phi[maxn+];
  7.  
  8. void phi_table(int n) { // O(nlogn) n以内欧拉表
  9. int i, j;
  10. for(i=;i<=n;i++)
  11. phi[i] = i;
  12.  
  13. for(i=;i<=n;i+=)
  14. phi[i] /= ;
  15.  
  16. for(i=;i<=n;i+=) {
  17. if(phi[i]==i) {
  18. for(j=i;j<=n;j+=i)
  19. phi[j] = phi[j] / i * (i - );
  20. }
  21. }
  22.  
  23. for(int i=;i<=n;i++) { // 前缀和
  24. phi[i] += phi[i-];
  25. }
  26. }
  27.  
  28. int main()
  29. {
  30. phi_table();
  31. int T, t = , n;
  32. cin>>T;
  33. while(t++<T) {
  34. scanf("%d", &n);
  35. printf("%d %d %d\n", t, n, phi[n]*+);
  36. }
  37. return ;
  38. }

B - Super A^B mod C

题目大意:

计算A^B (mod C)的结果,其中1<=A,C<=1000000000,1<=B<=10^1000000。

分析及代码:

B的数位长度达到了1000000位,即使利用快速幂logn的算法也有些勉强。。。

依稀记得有一个欧拉定理(费马小定理),计算当m为素数时a^b % m结果为a^(b%(m-1)),指数立刻收缩到了ll范围内。

这里需要用到a和m不互质情况下的欧拉降幂公式:

至于为什么我AC的代码指数没有加上phi(C)也过了,我也不懂O.O

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. const int maxn = ;
  7. typedef long long ll;
  8. ll a, c;
  9. char b[maxn];
  10.  
  11. ll phi(ll x) { // 欧拉函数
  12. ll res = x;
  13. for(int i=;i<=x/i;i++) {
  14. if(x%i==) {
  15. res = res/i*(i-);
  16. while(x%i==) x/=i;
  17. }
  18. }
  19. if(x>) res = res/x*(x-);
  20. return res;
  21. }
  22.  
  23. ll pow(ll a, ll n) { // 快速幂
  24. ll res = ;
  25. while(n) {
  26. if(n&) res = res * a % c;
  27. a = a*a % c;
  28. n >>= ;
  29. }
  30. return res;
  31. }
  32.  
  33. int main() {
  34. while(scanf("%lld", &a)!=EOF) {
  35. scanf("%s", b);
  36. scanf("%d", &c);
  37. ll exp = , p = phi(c);
  38. for(int i=;b[i];i++) {
  39. exp *= ;
  40. exp += b[i]-'';
  41. exp %= p;
  42. }
  43. // exp += p;
  44. printf("%lld\n", pow(a, exp));
  45. }
  46. return ;
  47. }

D - The Euler function

题目大意:

求一段区间的欧拉函数值的和。(2<a<b<3000000)

分析及代码:

欧拉函数裸题,使用O(nlogn)欧拉筛预处理。

(预先求前缀和的算法比直接区间求和要慢。。。)

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. const int maxn = ;
  6. typedef long long ll;
  7. ll phi[maxn];
  8.  
  9. void phi_table(int n)
  10. {
  11. int i, j;
  12. for(i=;i<=n;i++)
  13. phi[i] = i;
  14.  
  15. for(i=;i<=n;i+=)
  16. phi[i] /= ;
  17.  
  18. for(i=;i<=n;i+=) {
  19. if(phi[i]==i) {
  20. for(j=i;j<=n;j+=i)
  21. phi[j] = phi[j] / i * (i - );
  22. }
  23. }
  24.  
  25. for(int i=;i<=n;i++) {
  26. phi[i] += phi[i-];
  27. }
  28. }
  29.  
  30. int main()
  31. {
  32. phi_table();
  33. int a, b;
  34. while(scanf("%d %d", &a, &b)!=EOF) { // 此题直接写for循环更快
  35. printf("%lld\n", phi[b]-phi[a-]);
  36. }
  37. return ;
  38. }

E - Strange Way to Express Integers

题目大意:

中国剩余定理裸题。。。

分析及代码:

还不是特别熟悉,网上找了份mi不互质的模板,稍微改改就直接A了。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. typedef long long ll;
  7. const int maxn = ;
  8. ll exgcd(ll a, ll b, ll& x, ll& y) {
  9. ll d = a;
  10. if(b!=) {
  11. d = exgcd(b, a%b, y, x);
  12. y -= (a/b) * x;
  13. } else {
  14. x = ; y = ;
  15. }
  16. return d;
  17. }
  18.  
  19. ll a[maxn], m[maxn], n;
  20. ll CRT() {
  21. if (n == ) {
  22. if (m[] > a[]) return a[];
  23. else return -;
  24. }
  25. ll x, y, d;
  26. for (int i = ; i < n; i++) {
  27. if (m[i] <= a[i]) return -;
  28. d = exgcd(m[], m[i], x, y);
  29. if ((a[i] - a[]) % d != ) return -; //不能整除则无解
  30. ll t = m[i] / d;
  31. x = ((a[i] - a[]) / d * x % t + t) % t; //第0个与第i个模线性方程的特解
  32. a[] = x * m[] + a[];
  33. m[] = m[] * m[i] / d;
  34. a[] = (a[] % m[] + m[]) % m[];
  35. }
  36. return a[];
  37. }
  38.  
  39. int main() {
  40. while(scanf("%lld", &n)!=EOF) {
  41. for(int i=;i<n;i++) {
  42. scanf("%lld %lld", &m[i], &a[i]);
  43. }
  44. printf("%lld\n", CRT());
  45. }
  46. return ;
  47. }

F - C Looooops

题目大意:

求A + Cx = B (mod 2^k) 的x最小正整数解。

分析及代码:

上式变形得到

C*x + 2^k*y = B-A

利用扩展欧几里得ax+by=gcd(a,b)解该同余方程,得到x。

  • 若 (B-A) % gcd(a, b) 不为0,则无解。
  • 否则 x = x * (B-A) / gcd(a, b) ,得到 原方程的特解。
  • 原方程的全部解为 x + m * C / gcd(a, b), m∈Z
    • 令 s = C / gcd(a, b)
    • 所以最小的整数解为   (x%s + s) % s
  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. typedef long long ll;
  7. // d = gcd(a, b) = ax + by
  8. ll exgcd(ll a, ll b, ll& x, ll& y) {
  9. ll d = a;
  10. if(b!=) {
  11. d = exgcd(b, a%b, y, x);
  12. y -= (a/b) * x;
  13. } else {
  14. x = ; y = ;
  15. }
  16. return d;
  17. }
  18. // Ax = B (mod C)
  19. ll solve(ll A, ll B, ll C){
  20. ll x, y;
  21. ll d = exgcd(A, C, x, y);
  22. if(B%d!=){
  23. return -; // 无解
  24. }
  25. x *= B/d;
  26. ll s = C/d;
  27. return (x%s + s)%s;
  28. }
  29. int main()
  30. {
  31. int A, B, C, k;
  32. while(scanf("%d %d %d %d", &A, &B, &C, &k)!=EOF && A+B+C+k) {
  33. ll ans = solve(C, B-A, (ll)<<k); // A+Cx = B (mod 2^k)
  34. if(ans==-) {
  35. printf("FOREVER\n");
  36. } else {
  37. printf("%lld\n", ans);
  38. }
  39. }
  40. return ;
  41. }

G - Divisors

题目大意:

求组合数C(n, k)的因子个数。(0 ≤ k ≤ n ≤ 431)

分析及代码:

一看n,k都不大,直接将定义式的连乘项分解,统计每个素因子的出现次数。

然后有那啥公式,每个素因子个数+1后再相乘即为答案,交一发T了。

加上素数筛,还是T了。优化 了下,T了。改对n,k的记忆化,还是T了。

。。。

来学习一下求n!某个因子个数的方法:(去年博客

  1. // 公式:cnt = [n/p] + [n/p^2] + [n/p^3] +...+ [n/p^k]
  2.  
  3. // 核心代码:
  4.  
  5. int cnt = ;
  6.  
  7. while(n) {
  8.   cnt += n/p;
  9.  
  10.   n /= p;
  11.  
  12. }

终于AC的代码:

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cstring>
  5. using namespace std;
  6. const int maxn = ;
  7. int cnt[maxn], n, k;
  8. int p[maxn], num;
  9. void init() {
  10. for(int i=;i<maxn;i++) {
  11. bool isp = true;
  12. for(int j=;j*j<=i;j++) {
  13. if(i%j==) {
  14. isp = false;
  15. break;
  16. }
  17. }
  18. if(isp) p[num++] = i;
  19. }
  20. }
  21.  
  22. int cal(int n, int p) {
  23. int res = ;
  24. while(n) {
  25. res += n/p;
  26. n /= p;
  27. }
  28. return res;
  29. }
  30. int main()
  31. {
  32. init();
  33. while(scanf("%d %d", &n, &k)!=EOF) {
  34. long long ans = ;
  35. for(int i=;i<num && p[i]<=n;i++) { // 没有p[i]<=n TLE!!!
  36. long long cnt = ;
  37. cnt += cal(n, p[i]);
  38. cnt -= cal(k, p[i]);
  39. cnt -= cal(n-k, p[i]);
  40. ans *= (cnt+);
  41. }
  42. printf("%lld\n", ans);
  43. }
  44. return ;
  45. }
  1.  
  1.  

H - 青蛙的约会

题目大意:

同F题,求同余方程 x-y + (m-n) * k = 0 (mod L) k的最小正整数解。

分析及代码:

按照F的推导过程慢慢推吧。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. using namespace std;
  5. typedef long long ll;
  6. // d = gcd(a, b) = ax + by
  7. ll exgcd(ll a, ll b, ll& x, ll& y) {
  8. ll d = a;
  9. if(b!=) {
  10. d = exgcd(b, a%b, y, x);
  11. y -= (a/b) * x;
  12. } else {
  13. x = ; y = ;
  14. }
  15. return d;
  16. }
  17. // Ax = B (mod C)
  18. ll solve(ll A, ll B, ll C){
  19. ll x, y;
  20. ll d = exgcd(A, C, x, y);
  21. if(B%d!=){
  22. return -; // 无解
  23. }
  24. x *= B/d;
  25. ll s = C/d;
  26. return (x%s + s)%s;
  27. }
  28.  
  29. int main()
  30. {
  31. ll x, y, m, n, L;
  32. cin>>x>>y>>m>>n>>L;
  33. ll ans;
  34. if(m>n) ans = solve(m-n, y-x, L); // m-n>0
  35. else ans = solve(n-m, x-y, L);
  36. if(ans==-) {
  37. printf("Impossible\n");
  38. } else {
  39. printf("%lld\n", ans);
  40. }
  41. return ;
  42. }

I - Semi-prime H-numbers

题目大意:

定义类似4*k+1的正整数为H数。H数分为两种,H素数和H合数,合数中只能分解成两个H素数相乘形式的为H半素数。

求一个区间内H半素数的个数。

分析及代码:

模仿素数筛的写法,很容易实现O(nlogn)的H素数筛法。

在筛选过程中,将H数为标记为三种类别,素数、半素数、合数。

最后将所有含有半素数标记的取出,采用upper_bound二分查找可以快速得到答案。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cstring>
  5. using namespace std;
  6. const int maxn = ;
  7. int Htype[maxn]; // 0:prime 2:semi-prime 1:composite
  8. //int p[maxn], num;
  9. int pp[maxn], num2;
  10. void init() {
  11. // Htype[1] = isp[5] = 0;
  12. for(int i=;i<maxn;i+=) {
  13. if(!Htype[i]) {
  14. //p[num++] = i;
  15. if(i<maxn/i) Htype[i*i] = ;
  16.  
  17. for(int j=*i;j<maxn;j+=i) {
  18. if(j%==) {
  19. Htype[j] = ;
  20. if((j/i)%== && !Htype[j/i])
  21. Htype[j] = ;
  22. }
  23. }
  24. }
  25. }
  26.  
  27. for(int i=;i<maxn;i+=) {
  28. if(Htype[i]==) {
  29. pp[num2++] = i;
  30. }
  31.  
  32. }
  33. }
  34.  
  35. int main()
  36. {
  37. init();
  38. int h;
  39. while(scanf("%d", &h)!=EOF && h) {
  40. printf("%d ", h);
  41. printf("%d\n", upper_bound(pp, pp+num2, h) - pp);
  42. }
  43. return ;
  44. }

(未完待续)

数论专场 Day9 部分题解的更多相关文章

  1. DAY 3 数论专场

    2019-07-23 今天的题目一个比一个神仙,很早之前就在讨论今天是不是晚上回宾馆就没脑子了,后来发现,是中午.... 一上午就讲了一个PPT,然而标题就两个子---数论... 这谁顶的住....整 ...

  2. SPOJ - POLYNOM Polynomial(数论乱搞)题解

    题意 :给你n个数,问你是否存在一个多项式(最多三次方)满足f(i)= xi. 思路:讲一个神奇的思路: x3 - (x - 1)3 = 3x2 - 3x + 1 x2 - (x - 1)2 = 2x ...

  3. 【CYH-02】noip2018数论模拟赛:赛后题解

    1.小奔的矩阵 2.大奔的方案 3.小奔与不等四边形 4.小奔的方案 当然本次比赛肯定难度不会仅限于此啦!后续还会--

  4. 【数论】8.30题解-prime素数密度 洛谷p1835

    prime 洛谷p1835 题目描述 给定区间[L, R](L <= R <= 2147483647, R-L <= 1000000),请计算区间中 素数的个数. 输入输出 输入 两 ...

  5. NOI2010能量采集(数论)

    没想到NOI竟然还有这种数学题,看来要好好学数论了…… 网上的题解: 完整的结题报告: 首先我们需要知道一个知识,对于坐标系第一象限任意的整点(即横纵坐标均为整数的点)p(n,m),其与原点o(0,0 ...

  6. 【LOJ#3096】[SNOI2019]数论

    [LOJ#3096][SNOI2019]数论 题面 LOJ 题解 考虑枚举一个\(A\),然后考虑有多少个合法的\(B\). 首先这个数可以写成\(a_i+kP\)的形式,那么它模\(Q\)的值成环. ...

  7. NOIp2017——追求那些我一直追求的

    谨以此祭奠我即将爆炸的NOIP2017. $Mingqi\_H\ \ 2017.09.24$ Day -47 突然发现半年来自己从来没有写对过SPFA,最近几天才发现自己的板子一直是错的...赶紧找个 ...

  8. CSU训练分类

    √√第一部分 基础算法(#10023 除外) 第 1 章 贪心算法 √√#10000 「一本通 1.1 例 1」活动安排 √√#10001 「一本通 1.1 例 2」种树 √√#10002 「一本通 ...

  9. 【CodeForces】585 E. Present for Vitalik the Philatelist

    [题目]E. Present for Vitalik the Philatelist [题意]给定n个数字,定义一种合法方案为选择一个数字Aa,选择另外一些数字Abi,令g=gcd(Ab1...Abx ...

随机推荐

  1. STM32 Keil仿真调试

    引用:http://blog.sina.com.cn/s/blog_3c63d2bd0102vt9a.html 问题描述:使用MDK进行软件设计时没有使用ST官方的模板而是手动建立的工程,使用ST官方 ...

  2. PROJECT | 四则运算UI设计 - PSP表格&需求分析

    PSP表格(TP版) 需求分析 [GUI编程语言选择] 考虑到Java编写GUI效率偏低且界面不算特别美观(即使有Windowbuilder插件帮助),所以我们使用控件更多,开发效率更高,具有集成开发 ...

  3. Blahut-Arimoto algorithm Matlab源码

    For a discrete memoryless channel , the capacity is defined as where  and  denote the input and outp ...

  4. BZOJ2152 聪明可可 点分治

    题意传送门 思路:基本的点分治思路,num数组记录从u点开始路径长度分别为1或者2或者3的路径长度(取模3意义下),然后做一个简单的容斥就好了. 为了避免计数的麻烦,<u,u>这样的点单独 ...

  5. du和df

    du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在 的,没有被删除的.(-s:summarize 仅显示总计,只列出最后加总的值) df,disk ...

  6. python读文件判断是否已到EOF

    python读文件判断是否已到EOF,也即结尾,一般其它语言都是以EOF直接来判断的,比如 if ( fp.read(chunk_size) == EOF), 但python到结尾后是返回空字符串的, ...

  7. GCRoots 对象

    GC Roots 虚拟机栈(栈帧中的本地变量表)中引用的对象 方法区中的类静态属性引用的对象 方法区中的常量引用的对象 原生方法栈(Native Method Stack)中 JNI 中引用的对象 可 ...

  8. php设置时区和strtotime转化为时间戳函数

    date_default_timezone_set('PRC');//设置中华人民共和国标准时间 strtotime — 将任何英文文本的日期时间描述解析为 Unix 时间戳 格式:int strto ...

  9. The Preliminary Contest for ICPC Asia Nanjing 2019 C. Tsy's number 5

    https://nanti.jisuanke.com/t/41300 题意:求\(\sum_{i=1}^n\phi(i)\phi(j)2^{\phi(i)\phi(j)}\) \(f_i=\sum_{ ...

  10. MySql查询分页数据

    MySql查询分页数据