ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++笔试题模版汇总(四)

2020-03-11 10:06:02  阅读:229  来源: 互联网

标签:return int 模版 笔试 C++ ++ res include SG


1、质数

//1、试除法
bool is_prime(int n)
{
    if (n < 2) return false;
    for (int i = 2; i <= n; i ++)
        if (n % i == 0)
            return false;
    return true;
}
//2、试除法优化
/*如果d/n能整除,那么n/d / n也能整除。比如n = 12, 3和4都是他的约数,n的约数都是成对出现的  。在枚举的时候我们可以只枚举没对较小的一个就可以了。
*/
bool is_prime(int n)
{
    if (n < 2) return false;
    //i <= n / i 时间复杂度根号n
    for (int i = 2; i <= n / i; i ++)
        if (n % i == 0)
            return false;
    return true;
}

2、分解质因数

bool divide(int n)
{
    //i <= n / i 时间复杂度根号n
    for (int i = 2; i <= n / i; i ++)
        if (n % i == 0)//i一定是质数
        {
            int s = 0;
            while(n % i == 0)
            {
                n /= i;
                s ++;
            }
            printf("%d %d\n", i, s);//对于每个正整数ai,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。
        }
    //每个质因数的底数和指数,每个底数和指数占一行
    if (n > 1) printf("%d %d\n", n, 1);
    puts("");
}

3、筛质数

1~n中质数有n/ln(n)个质数,按顺序删除每个数的倍数,最后剩下的就是质数。

int primes[N], cnt;//primes[]存储所有素数
bool st[N];//st[x]存储x是否被筛掉
//朴素做法
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++){//从2开始枚举
        
        if (!st[i])primes[cnt ++ ] = n;//当前数没有被筛过,则是个质数
        for (int j = i + i; j <= n; j +=i) //j = i + i,将n的倍数删除掉
            st[j] = true;//标记为true
    }
}
 
//埃式筛法-O(nloglogn)
void get_primes(int n) {
    for(int i = 2; i <= n; i++) {
        if(!st[i]){ 
            prime[cnt++] = i;
            for(int j = i; j <= n; j += i)
                st[j] = true;
        }
    } 
}
 
//线性筛法-O(n), n = 1e7的时候基本就比埃式筛法快一倍了
//算法核心:x仅会被其最小质因子筛去
void get_prime(int x) {
    for(int i = 2; i <= x; i++) {
        if(!st[i]) prime[cnt++] = i;//找到质数
        for(int j = 0; prime[j] <= x / i; j++) {//从0开始找j倍数
            //对于任意一个合数x,假设pj为x最小质因子,当i<x/pj时,一定会被筛掉
            st[prime[j]*i] = true;//倍数直接标记
            if(i % prime[j] == 0) break;
            /*
            1.i%pj == 0, pj定为i最小质因子,pj也定为pj*i最小质因子
            2.i%pj != 0, pj定小于i的所有质因子,所以pj也为pj*i最小质因子
            */
        }
    }
} 

4、试除法求约数

1、从小到大枚举所有约数

2、只枚举每一对约数较小的

3、如果i != n / i,才加进去

#include <iostream>
#include <algorithm>
#include <vector>//存一个数所有约数
 
using namespace std;
 
vector<int> get_divisors(int n)
{
    vector<int> res;
    
    for (int i = 1; i <= n / i; i ++)//循环遍历找约数
        if (n % i == 0)//如果是一个约数,则存起来
        {
            res.push_back(i);
            if (i != n / i) res.push_back(n / i);//可能会出现n = i*i,两个余数相同的情况,所以需要判断一下
        }
    //最后将约数排个序
    sort(res.begin(), res.end());
    return res;
}
 
int main()
{
    int n;
    cin >> n;
    
    while (n --)
    {
        int x;
        cin >> x;
        auto res = get_divisors(x);//dedaox所有的约数
        //循环遍历输出x的约数
        for (auto t : res) cout << t << ' ';
        cout << endl;
    }
    return 0;
}

5、约数之和

实际上就是n的所有约数个数加到一块,如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)

#include <iostream>
#include <algorithm>
#include <unordered_map>
 
using namespace std;
 
typedef long long LL;
 
const int mod = 1e9 + 7;
 
int main()
{
    int n;
    cin >> n;
    
    //定义哈希表存所有底数和指数
    unordered_map<int, int> primes;
    
    while (n --)
    {
        int x;
        cin >> x;
        //遍历求x质因数
        for (int i = 2; i <= x / i; i ++)
            while (x % i == 0)
            {
                x /= i;
                //i的质因数指数+1
                primes[i] ++ ;//存质因数指数
            }
        //判断如果x>1说明x是一个比较大的质因数
        if (x > 1) primes[x] ++;//将剩下的质因数加上就好了
    }
    
    //枚举所有的质因数
    LL res = 1;
    //带入求和公式:
    for (auto prime : primes) 
    {
        //1、枚举每一个质数
        int p = prime.first, a = prime.second;//p表示质数的底数,a表示质数的底数
        LL t = 1;//t来存每一部分的总和
        //2、先求P的0次方+...+P的a次方,然后每次对t进行操作: t = p * t + 1
        //t = 1,p + 1;第二次t = 2,p^2 + p + 1;第a次p^a +...+1
        while (a --) t = (t * p + 1) % mod;
        res = res * t % mod;
    }
    cout << res << endl;//得到结果
    
    return 0;
}

6、求最大公约数(欧几里得)

如果d能整除a,d能整除b,则d能整除a+b,也能整除(ax + by);则(a, b)的最大公约数 = (b, a mod b);

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;//b如果不是0返回a%b最大公约数,如果为0则返回a
}

7、求欧拉函数

筛法求欧拉函数

1、如果这个数是质数,1~p-1都是质数

2、如果i % primes[j] == 0,说明i是p[j]的质因子则有:

3、如果i % primes[j] != 0,pj是(i*pj)的最小质因子,则有:

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    
    while (n --)
    {
        int a;
        cin >> a;
        int res = a;//答案用res表示
        //分解质因数
        for (int i = 2; i <= a / i; i ++)
            if (a % i == 0)
            {
                res = res / i * (i - 1);//等价于i*(1-1/i)
                while (a % i == 0) a /= i; 
            }
        if (a > 1) res = res / a*(a - 1);//如果还没除完,再除一次
        
        cout << res << endl;    
    }
    
    return 0;
}

//筛选法求欧拉函数

//primes存的每一个质数, cnt存质数下标
int primes[N], cnt;
//欧拉函数
int phi[N];
bool st[N];//表示每个数是否被筛到
 
LL get_eulers(int n)
{
    phi[1] = 1;//定义第一个
    for (int i = 2; i <= n; i ++)
    {
        if (!st[i])//如果没被筛过
        {
            primes[cnt ++] = i;
            phi[i] = i - 1;//如果这个数是质数,1~p-1都是质数
        }
        //从小到大枚举所有质数
        for (int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;//标记已经筛过
            if (i % primes[j] == 0) //break;//一个优化变成线性
            {
                //i % primes[j] == 0,说明i是p[j]的质因子
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            //如果i % primes[j] != 0,pj是(i*pj)的最小质因子
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
    
    LL res = 0;//定义总和
    for (int i = 1; i <= n; i ++) res += phi[i];//求总和
    return res;
}

8、快速幂

快速求出来a^k mod p的结果

int qmi(int a, int k, int p)
{
    int res = 1;//答案
    while (k)
    {
        //第一次迭代从a^0开始,1开始
        if (k & 1) res = (LL) res * a % p;//如果当前k的末位是1,则是第一次迭代
        //把k的末位删除
        k >>= 1;
        //把a变成下一个
        a = (LL)a * a % p;//a平方一下
        
    }
    return res;//返回res
}

//Example-求逆元
#include <iostream>
#include <algorithm>
 
using namespace std;
 
typedef long long LL;
 
//a^k % p
int qmi(int a, int k, int p)
{
    int res = 1;//答案
    while (k)
    {
        //第一次迭代从a^0开始,1开始
        if (k & 1) res = (LL) res * a % p;//如果当前k的末位是1,则是第一次迭代
        //把k的末位删除
        k >>= 1;
        //把a变成下一个
        a = (LL)a * a % p;//a平方一下
        
    }
    return res;//返回res
}
 
int main()
{
    int n;
    //读入数据比较多yong scanf
    scanf("%d", &n);
    while (n --)
    {
        int a, p;
        scanf ("%d%d", &a, &p);
        
        int res = qmi(a, p - 2, p);//费马定理,求出结果
        if (a % p) printf("%d\n", res);//说明d不是p的倍数,输出res
        //如果p = 2比较特殊,是0次方,需要特判
        else printf("impossible\n");//d是p的倍数说明一定无解
    }
    
    return 0;
}

9、扩展欧几里得算法-线性同余方程

概念:给定a, b, m,求整数x,使得: ax = b(mod m);

举例:2x = 3 (mod 6) 无解

          4x = 3 (mod 5) :4*某一个数 同于于 4*某一个数/5的余数是3. x可以等于 2,7等。

等式变形:

ax = b(mod m) 等价于 存在一个整数y属于z,使得 ax = m*y + b  --> ax - my = b --> y` = y, ax + my` = b;

注意:该式子能成立的条件是b能整除(a,m)最大公约数,(a, m) | b, 那么就有解,否则一定无解。
 

int exgcd(int a, int b, int &x, int &y)
{
    //return b ? gcd(b, b % a) : a;
    if (!b) //如果b = 0,ax + by = a
    {
        //得到一组解
        x = 1, y = 0;
        return a;//如果b = 0,返回a
    }
    //by + (a mod b)x = (a, b)最大公约数d
    int d = exgcd(b, a % b, y, x);//存下最大公约数,翻转了一下
    //a mod b = a - (a / b)下取整 * b带入
    //by + (a - (a / b)下取整 * b)x = d;
    //展开整理:ax + b (y - (a/b)*x)
    //得到a的系数不变为a,y的系数变成:y - (a/b)*x
    y -= a / b * x;
    
    return d;
}

10、高斯消元

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
 
const int N = 110;
const double eps = 1e-6;
int n;
double a[N][N];//存矩阵
 
int gauss()
{
    int c, r;//定义行和列
    //1、从第0行第0列开始,找到绝对值最大的一行
    for (c= 0, r = 0; c < n; c ++)
    {
        int t = r;
        for (int i = r; i < n; i ++)
            //如果找到绝对值比较大的一列,fabs表示绝对值函数
            if (fabs(a[i][c] > fabs(a[t][c])))
                t = i;//换成当前列
        //因为值是double类型,所以为了防止出现精度问题我们需要特判一下
        if (fabs(a[t][c]) < eps) continue;//fabs是返回浮点数绝对值,如果当前是0,返回continue
        
        //2、把当前绝对值最大一行换到最上面去
        for (int i= c; i <= n; i ++) swap(a[t][i], a[r][i]);
        //3、将换上去的那行第一个数化成1
        //从最后一个开始换
        for (int i = n; i >= c; i --) a[r][i] /= a[r][c];
        //4、将下面所有行的当前列,消成0
        for (int i = r + 1; i < n; i ++)
            if (fabs(a[i][c]) > eps)//从第二列开始,如果第一个数大于零才进行消0操作
                for (int j = n; j >= c; j --)//把第一行通过乘除操作,是的第一行第一个数与第二行第一个数相同,然后进行相减
                    a[i][j] -= a[r][j] * a[i][c];//a[r][j] * a[i][c]:第一行的数*第i行第一个数的值
        //操作完记得 r ++
        r ++;
    }
    if (r < n)//5、结果不到n个,可能存在无解或者无穷多个解
    {
        //如果出现0 = 非零情况,则无解
        for (int i = r; i < n; i ++) 
            if (fabs(a[i][n]) > eps)//每行最后一个存在>0的结果,即0 = 非零情况,则无解
                return 2;//无解
        return 1;//否则有无穷多种解
    }
    //6、找到三角结构,就互相消元。倒着把方程消一遍,把除了第一个数以外后面的数消成0
    for (int i = n - 1; i >= 0; i --)
        for (int j = i + 1; j < n; j ++)
            //从第最后一个i个开始消
            //把当前这方程除了xi这个系数之外所有系数消成0,减去他的系数*他的值
            a[i][n] -= a[i][j] * a[j][n];//a[j][n]是xj的值
    
    
    return 0;//如果r = n,则只有唯一解
}
 
int main()
{
    cin >> n;//n行n列
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n + 1; j ++)
            cin >> a[i][j];//构建输入矩阵
    
    //高斯消元
    int t = gauss();
    //得到三种解:唯一解、无穷多种解、无解
    if (t == 0)//t = 0唯一解
    {
        for (int i = 0; i < n; i ++) printf("%.2f\n", a[i][n]);
    }//t = 1无穷多种解
    else if (t == 1) puts("Infinite group solutions");
    //t = 2无解 
    else puts("No solution");
    
    return 0;
}

11、求组合数

//递归法求组合数
// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )
    for (int j = 0; j <= i; j ++ )
        if (!j) c[i][j] = 1;//如果是第一个数0,则标记1
        else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;////按照公式来

//
/*首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N]
如果取模的数是质数,可以用费马小定理求逆元*/
int qmi(int a, int k, int p)    // 快速幂模板
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

// 预处理阶乘的余数和阶乘逆元的余数
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
    fact[i] = (LL)fact[i - 1] * i % mod;
    infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}

12、博弈论

定理: NIM博弈先手必胜,当且仅当 A1 ^ A2 ^ … ^ An != 0

方法:找奇数台阶,如果奇数台阶异或!=0,则胜利。

充要条件:所有奇数级台阶所有石子异或起来不等于0.

#include <iostream>
#include <algorithm>
 
using namespace std;
 
int main()
{
    int n;
    int res = 0;
    
    scanf ("%d", &n);
    for (int i = 1; i <= n; i ++)
    {
        int x;
        scanf ("%d", &x);
        if (i % 2) res ^= x;//所有奇数级台阶所有石子异或起来不等于0.
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

Mex运算
设S表示一个非负整数集合。定义mex(S)为求出不属于集合S的最小非负整数的运算,即:找到集合当中不存在的最小自然数。
mex(S) = min{x}, x属于自然数,且x不属于S

SG函数

在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达节点y1, y2, …, yk,定义SG(x)为x的后继节点y1, y2, …, yk 的SG函数值构成的集合再执行mex(S)运算的结果,即:
SG(x) = mex({SG(y1), SG(y2), …, SG(yk)})
特别地,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即SG(G) = SG(s)。SG(终点)=0,存在y1, y2, ... ,yn的局面。图的最后一个点(第二条路径)即终点定义为0,终点前一个点不存在最小自然数则为1,往后一个数不存在最小自然数除了0和1,那么就是2了,如此递推,最开始那个不存在最小自然数为3。

结论:SG = 0,必败,SG != 0必败。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
 
using namespace std;
 
const int N = 110, M = 10010;
 
int n, m;
int s[N], f[M];//s表示谁的个数,f表示SG的值
 
//求sg
int sg(int x)
{
    //记忆化搜索--优化
    if (f[x] != -1) return f[x];//如果每个状态都被算过直接返回结果
    
    //哈希表存他所有可以到的局面
    unordered_set<int> S;
    for (int i = 0; i < m; i ++)
    {
        //当前数的个数
        int sum = s[i];
        //如果当前个数>=sum,才可以取这些数
        if (x >= sum) S.insert(sg(x - sum));
    }
    //判断当前集合当中不存在的点
    for (int i = 0; ; i ++)
        if (!S.count(i))//如果当前数不存在,当前的值就是i
            return f[x] = i;
}
 
int main()
{
    cin >> m;//读入m个数
    //输入操作
    for (int i = 0; i < m; i ++) cin >> s[i];
    cin >> n;//读入n,求的SG,每堆的个数
    
    memset(f, -1, sizeof f);//用记忆化搜索
    
    //求每一堆的个数
    int res = 0;
    for (int i = 0; i < n; i ++)
    {
        int x;
        cin >> x;
        res ^= sg(x);
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

 

 

 

 

 

标签:return,int,模版,笔试,C++,++,res,include,SG
来源: https://blog.csdn.net/qq_27262727/article/details/104789231

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有