zoukankan      html  css  js  c++  java
  • 【洛谷】训练场_简单数学篇(不全)

    P1865 A%B Problem

    题意:

    求区间质数的个数。

    分析:

    简单的质数打表模板题,根据题目再添加一点限制条件即可AC。

    因为m最大才1e6,所以打表是可以的。

    简单说说打表的思路:(埃式筛法)

    从最小的质数2开始,将表中所有2的倍数都划去,然后再到质数3,将表中所有3的倍数都划去......以此类推。

    0,1先特殊处理一下。

     1 // 参考《挑战程序设计竞赛》P119
     2 bool is_prime[1000005];
     3 int prime[1000005];
     4 
     5 // O(nloglogn)
     6 void prime_table(){ // 这里的范围定义为 1e6
     7     is_prime[0] = is_prime[1] = false; // 特殊处理 0,1
     8     for(int i = 2; i <= 1000000; i++) is_prime[i] = true;
     9     for(int i = 2; i <= 1000000; i++){
    10         if(is_prime[i]){
    11             // 把 质数i 的倍数从表里划去
    12             for(int j = i+i; j <= 1000000; j+=i) is_prime[j] = false; 
    13         }
    14     }
    15 }
    模板代码
     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 int n, m;
     6 bool is_prime[1000005];
     7 
     8 void sieve(){
     9     for(int i = 0; i <= 1000000; i++) is_prime[i] = true;
    10     is_prime[0] = is_prime[1] = false;
    11     for(int i = 2; i <= 1000000; i++){
    12         if(is_prime[i]){
    13 //            prime[p++] = i;
    14             for(int j = 2 * i; j <= 1000000; j+=i) is_prime[j] = false;
    15         }
    16     }
    17 }
    18 
    19 int main()
    20 {
    21     sieve();
    22     while(cin >> n >> m){
    23         int l, r, ans;
    24         for(int a = 0; a < n; a++){
    25             cin >> l >> r;
    26             ans = 0;
    27             if(l > m || r > m || l <= 0 || r <= 0){
    28                 cout << "Crossing the line
    ";
    29             }
    30             else{
    31                 for(int i = l; i <= r; i++){
    32                     if(is_prime[i]) ans++;
    33                 }
    34                 cout << ans << endl;
    35             }
    36         }
    37     }
    38     return 0;
    39 }
    AC代码

    下一题:

    P1372 又是毕业季Ⅰ

    题意:

    在n个数中(每个数的大小以次是1~n)中,找到k个数中的最大公约数。

    分析:

    (请拿出笔和纸来一起列下式子分析下,如果是数学大牛的话,请忽略这段话)

    (感谢kkkse03的题解)

    在n个数里,每个数的大小是1,2,3,...,n-1,n;

    所取的k个数分别是X1,X2,X3,...,Xk-1, Xk;

    设最大公约数为a,

    则有 X1 >= 1a, X2 >= 2a,...,Xk >= ka ①;

    同时又因为 Xk <= n ②

    又①②得 ka <= n,转换一下就是 a <= [n/k] ([]为取整符号)

    另外,取[n/k],2*[n/k],3*[n/k],...,k*[n/k],满足最大公约数a = [n/k],且都小于等于n大于等于1,且互不相等,满足条件。

    (如果觉得还不清楚请看洛谷题解吧dbq)

    因此这就被当作是入门难度的题目处理了(代码确实很短)

     1 #include<iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int n, k;
     7     while(cin >> n >> k){
     8         cout << n / k << endl;
     9     }
    10     return 0;
    11 }
    AC代码

    也是一道辗转相除法的题目,运用了辗转相除法的思想:

    公约数a, y = ax + b (y >= ax)

    这样的思维才得出了以上关系式。

    下一题:

    P1582倒水

    题意:

    一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)

    显然在某些情况下CC无法达到目标,比如N=3,K=1。此时CC会重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以到达目标。

    现在CC想知道,最少需要买多少新瓶子才能达到目标呢?

    分析:

    相同容量时的瓶子才能合二为一→二叉树状图→2的次方!

    要最少的瓶子就是2的次方数相加的和比N大的最小值。

    N不是2的次方数的情况:

    留k瓶水,则要找k个2的次方数,

    当k!=1时,找比k/2大的2的次方数,然后N减去这个2的次方数;

    当k==1时,找比k大的2的次方数;

    N是2的次方数的情况:

    只要确认下N是不是2的次方数即可输出0;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 using namespace std;
     5 
     6 long long n, k;
     7 
     8 int main()
     9 {
    10     while(cin >> n >> k){
    11         long long num, ans;
    12         while(k>0 && n > 0){
    13             num = 1;
    14             if(k == 1){
    15                 while(num < n){
    16                     num *= 2;
    17                     if(num == n) ans = 0;
    18 //                    printf("k:%lld n:%lld num:%lld
    ", k, n, num);
    19 
    20                 }
    21                 ans = num - n;
    22 //                printf("k:%d n:%d num:%d
    ", k, n, num);
    23             }
    24             else {
    25                 while(num <= n / 2){
    26                     num *= 2;
    27                 }
    28 //                printf("k:%d n:%d num:%d
    ", k, n, num);
    29                 n -= num;
    30                 ans = n;
    31             }
    32             k--;
    33         }
    34         cout << ans << endl;
    35     }
    36     return 0;
    37 }
    AC代码

    下一题:

    P2158[SDOI2008]仪仗队

    题意:

    分析:

    题目很好懂,但怎么想都觉得很麻烦,因为N<=40000,不能开二维数组。

    (作者unsigned说这是一道欧拉函数题,tql)

    对unsigned的题解上的补充。

    欧拉函数(Eular(int n))的效果是输出比n小与n互质的个数。

    公式是:

    右式= x(1-1/p1)(i-1/p2)*...*(1-1/pn);

    为了防止爆数可以这样处理:

    右式=x*p1(p1-1)*p2(p2-1)*...*pn(pn-1);

     1 int eular(int n)
     2 {
     3     int ret=1,i;
     4     for(i=2;i*i<=n;i++) // 运用 筛法, 找 n 的因数
     5     {
     6         if(n%i==0)  // i 是 n 的因数, 且是质数
     7         {
     8             n/=i,ret*=i-1;
     9             while(n%i==0) n/=i,ret*=i;
    10         }
    11     }
    12     if(n>1) ret*=n-1; // n 本身变成了质数或者本来就是质数
    13     return ret;
    14 }
    欧拉函数模板
     1 void phi_table()
     2 {
     3     phi[0] = 0, phi[1] = 1; // 1的欧拉函数值为1, 唯一与1互质的数
     4     for(int i = 2; i < maxn; i++) phi[i] = i; // 先初始化为其本身
     5     for(int i = 2; i < maxn; i++){
     6         if(phi[i] == i){ // 如果欧拉函数值仍为其本身, 说明i为素数
     7             for(int j = i; j < maxn; j += i)// 把i的欧拉函数值改变, 同时也把能被素因子i整除的数的欧拉函数值改变
     8             phi[j] = phi[j] / i * (i - 1);
     9         }
    10     }
    11 }
    打表模板
     1 // 感谢 unsigned作者 精彩的分析
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5 
     6 int n;
     7 int prime[40002];
     8 
     9 void phi_table(){
    10     for(int i = 0; i <= 40000; i++) prime[i] = i;
    11     for(int i = 2; i <= 40000; i++){
    12         if(prime[i] == i){
    13             for(int j = i; j <= 40000; j += i)
    14             prime[j] = prime[j] / i * (i - 1);
    15         }
    16     }
    17 }
    18 
    19 int main()
    20 {
    21     phi_table();
    22     while(cin >> n){
    23         if(n == 1) { cout << 0 << endl; continue; }
    24         else{
    25             int ans = 2;
    26             for(int i = 2; i < n; i++) ans += prime[i] * 2;
    27             cout << ans + 1 << endl;
    28         }
    29     }
    30     return 0;
    31 }
    AC代码

    今天收获:

    复习了与gcd,质数,欧拉函数有关的数学题,数学题要多写,找规律。

    (数学不太好的我太吃亏了)

  • 相关阅读:
    [HIS] HIT行业常用名词及缩写定义
    String Split 和 Join
    深入解析字符串的比较方法:“==”操作符;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
    Oracle安装时先决条件检查失败的解决方案
    C#创建XML文件并保存
    关于SQL Server 数据库的备份
    为Windows 7添加“Internet打印”功能
    C#如何使用和开发自定义配置节
    C#中配置文件的使用
    键盘KeyCode值列表
  • 原文地址:https://www.cnblogs.com/Ayanowww/p/10849250.html
Copyright © 2011-2022 走看看