算法竞赛入门笔记整理

这篇博客主要介绍了C++在算法竞赛中的应用,重点讲解了STL的使用,包括lower_bound函数用于检索非递减序列,sort函数进行排序,以及vector和set、map等数据结构的操作。还提到了构造函数在结构体中的应用以及字符串和引用的相关知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断是否为素数

int is_prime(int n){
    if(n<=1) return 0;    #判断n<=1的情况
    int m=floor(sqrt(n) + 0.5);    #对n开根号之后四舍五入
    for(int i=2;i<=m;i++)
    	if(n % i == 0) return 0;
    return 1;
}

字符串格式转换sprintf函数

sprintf(存储的字符串,”输出格式控制符”,要保存的对应格式数据);

c++需要指定头文件的输入输出流和命名空间后,才能使用cin等函数

#include<iostream>
using namespace std;

声明静态常量可以用

const

引用&,参数按传引用的方式传递,可以直接修改变量,代替c语言中的指针变量

#include <iostream>
using namespace std;

void swap2(int &a,int &b){
    int t = a;
    a = b;
    b = t;
}

int main(){
    int a=3,b=4;
    swap2(a,b);
    cout<<a<<b;
    return 0;
}

字符串string:用getline函数读取一行数据,然后用这一行创建一个“字符串流”--ss,之后用cin读取ss的每一个被空格分隔的字符串。

#include <iostream>
#include <cstring>
#include <sstream>
using namespace std;

int main(){
    string line;
    while(getline(cin,line)){
        int sum = 0,x;
        stringstream ss(line);
        while(ss >> x) sum += x;
        cout << sum;
    }
    return 0;
}

结构体struct:可以包含成员变量和成员函数,可以替代复杂的class

  • 结构体Point中定义了一个Point函数,没有返回值,称为构造函数。构造函数在声明变量时调用,即Point a,b(1,2)调用了Point(1,2);
  • :x(x),y(y)表示把成员变量x初始化成参数x,成员变量y初始化成参数y;x和y的默认值是0。
#include <iostream>
using namespace std;

struct Point{
    int x,y;
    Point(int x=0,int y=0):x(x),y(y){}
};

Point operator +(const Point &A,Point &B){
    return Point(A.x+B.x,A.y+B.y);
}

ostream& operator <<(ostream &out,const Point &p){
    cout<<"("<<p.x<<","<<p.y<<")";
    return out;
}

int main(){
    Point a,b(1,2);
    a.x = 3;
    cout<<a+b<<"\n";
    return 0;
}

STL:cpp标准模板的使用

  • 检索
    lower_bound
    功能:查找非递减序列内第一个大于或等于元素x的位置
    返回值:如果找到元素x,返回该x的位置;否则返回数组a的长度n(可能会越界);
    用法:int p = lower_bound(a,a+n,x) - a;

  • 排序
    sort

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10000;

int main(){
    int n,q,x,a[maxn],kase = 0;
    while(scanf("%d%d",&n,&q) == 2 && n){
        printf("Case# %d:\n",++kase);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        sort(a,a+n)     //按升序顺序对a数组从0-n范围排序
        while(q--){
            scanf("%d",&x);
            int p = lower_bound(a,a+n,x) - a;    //在已排序数组a中查找x
            if(a[p] == x)    printf("%d found at %d\n",x,p+1);
            else printf("%d not found\n",x);
        }
    }
    return 0;
}
  • 不定长数组:vector
    创建一维不定长数组:vector<T> a;可以创建T类型的向量数组a,T可以是内置类型或结构体;
    创建二维数组,其中一维定长另一维不定长:vector<T> a[maxn];
    添加元素:a.push_back(b);
    删除元素:a.pop_back();
    数组大小:a.size();
    改变数组大小:a.resize(n+1);
    判定是否为空:a.empty();
    清空:a.clear();

     
  • 集合:set
    输入一个文本,找出所有不同的单词(连续的单词序列),按字典从小到大输出。单词不区分大小写。
    样例输入:
    Adventures in Disneyland Two blondes were going 
    to Disneyland when they came to a fork in the road. 
    The sign read:"Disneyland Left."So they went home.
    
    样例输出:
    a
    adventures
    blondes
    came
    disneyland
    fork
    going
    home
    in
    left
    read
    road
    sign
    so
    the
    they
    to
    two
    went
    were
    when
     
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <sstream>
    using namespace std;
    
    set<string> dict;    //string集合
    
    int main(){
        string s,buf;
        while(cin>>s){
            for(int i=0;i<s.length();i++){
                if(isalpha(s[i]))
                    s[i] = tolower(s[i]);
                else s[i] = ' ';
            }
            stringstream ss(s);
            while(ss >> buf) dict.insert(buf);
        }
        for(set<string>::iterator it = dict.begin();it!=dict.end();++it)
            cout<< *it << "\n";
        return 0;
    }
  • 映射:map
    反片语 (Uva 156)
    输入一些单词,找出所有满足如下条件的单词:该单词不能通过字母重排得到输入文本中的另外一个单词。输出时保留大小写,按字典序排列(所有大写字母在小写字母前面)。
    输入样例:
    ladder came tape soon leader acme RIDE lone Dreis peat
     ScAlE orb  eye  Rides dealer  NotE derail LaCeS  drIed
    noel dire Disk mace Rob dries
    #
    
    输出样例:
    Disk
    NotE
    derail
    drIed
    eye
    ladder
    soon
    #include <iostream>
    #include <string>
    #include <cctype>
    #include <map>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    map<string,int> cnt;
    vector<int> words;
    
    //将单词标准化
    string repr(const string& s){
        string ans = s;
        for(int i=0;i<ans.length();i++)
            ans[i] = tolower(ans[i]);
        sort(ans.begin(),ans.end());
        return ans;
    }
    
    int main(){
        int n=0;
        string s;
        while(cin>>s){
            if(s[0] == '#') break;
            words.push_back(s);
            string r = repr(s);
            if(!cnt.count(r)) cnt[r] = 0;
            cnt[r]++;
        }
        vector<string> ans;
        for(int i=0;i<words.size();i++)
            if(cnt[repr(words[i])] == 1)
                ans.push_back(words[i]);
        sort(ans.begin(),ans.end());
        for(int i=0;i<ans.size();i++)
            cout<<ans[i]<<"\n";
        return 0;
    }

  •  
<think>好的,我现在需要帮助用户了解算法竞赛中常用的数学基础概念和公式。用户提到参考了三个引用内容,我需要结合这些资料来整理答案。 首先,引用[1]提到《算法竞赛入门经典》的补充内容,包括数学基础章节,涉及数论、组合数学等。引用[3]的笔记提到了位运算、快速幂、状态压缩等内容。这些应该是数学基础中的重要部分。 接下来,我需要确定算法竞赛中常见的数学知识点。根据我的知识,数论、组合数学、概率与统计、线性代数、几何以及位运算相关的数学都是常见的。需要每个部分列出关键概念和公式。 数论方面,质数判断、欧几里得算法、模运算、欧拉定理、中国剩余定理都是基础。组合数学包括排列组合、容斥原理、生成函数。概率与统计可能需要期望和方差的计算。线性代数中的矩阵快速幂用于加速递推,高斯消元解方程组。几何部分涉及点线面的计算,凸包算法。位运算相关的快速幂、状态压缩技巧也很重要。 然后,要确保所有数学表达式使用正确的LaTeX格式,行内用$...$,独立公式用$$...$$。例如,质数判断的试除法条件写成$2 \leq d \leq \sqrt{n}$,欧几里得算法写成$\gcd(a,b) = \gcd(b, a\bmod b)$。 还要生成相关问题,参考示例中的结构,可能的问题包括数论应用、组合数学优化方法、矩阵快速幂的应用等。需要确保问题与内容相关,并引导深入学习。 最后,检查引用标注是否正确,每个引用在回答中适当的位置标注,例如质数判断部分引用[1],位运算部分引用[3]。同时,保持回答结构清晰,分点列出,便于用户理解。</think>### 算法竞赛中的数学基础概念与公式 算法竞赛中的数学知识是解题的核心工具之一,尤其在优化算法、推导公式、处理复杂逻辑时尤为重要。以下是常见的数学基础概念和公式分类整理: --- #### 1. **数论基础** - **质数与筛法** 判断质数的试除法条件:$2 \leq d \leq \sqrt{n}$ 埃拉托斯特尼筛法时间复杂度:$O(n \log \log n)$ 欧拉筛法(线性筛)时间复杂度:$O(n)$[^1] - **最大公约数(GCD)与扩展欧几里得算法** 欧几里得算法:$\gcd(a,b) = \gcd(b, a \bmod b)$ 贝祖定理:$ax + by = \gcd(a,b)$ 有整数解 - **模运算与同余方程** 快速幂公式:$a^b \bmod p = (a^{b/2} \cdot a^{b/2}) \bmod p$(递归分治) 欧拉定理:若 $\gcd(a,m)=1$,则$a^{\phi(m)} \equiv 1 \pmod{m}$,其中$\phi(m)$为欧拉函数 - **中国剩余定理(CRT)** 求解同余方程组: $$x \equiv a_1 \pmod{m_1}, \quad x \equiv a_2 \pmod{m_2}, \quad \cdots$$ 当$m_i$两两互质时,存在唯一解 --- #### 2. **组合数学** - **排列与组合公式** 组合数公式:$C(n,k) = \frac{n!}{k!(n-k)!}$ 递推关系:$C(n,k) = C(n-1,k) + C(n-1,k-1)$ 卢卡斯定理(大组合数取模):$C(n,k) \equiv \prod C(n_i,k_i) \pmod{p}$($n_i,k_i$为$n,k$的$p$进制分解) - **容斥原理** 计算并集大小: $$|A_1 \cup A_2 \cup \cdots \cup A_n| = \sum |A_i| - \sum |A_i \cap A_j| + \cdots + (-1)^{n+1}|A_1 \cap \cdots \cap A_n|$$ - **生成函数** 普通生成函数(OGF):$G(x) = \sum a_n x^n$ 指数生成函数(EGF):$G(x) = \sum \frac{a_n}{n!} x^n$ --- #### 3. **概率与期望** - **期望线性性** $E[X+Y] = E[X] + E[Y]$(即使$X$和$Y$不独立) 常见应用:几何分布期望(成功概率$p$,期望试验次数$\frac{1}{p}$) --- #### 4. **线性代数** - **矩阵快速幂** 用于加速递推关系(如斐波那契数列): $$F(n) = F(n-1) + F(n-2) \Rightarrow \begin{pmatrix} F(n) \\ F(n-1) \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^{n-1} \begin{pmatrix} F(1) \\ F(0) \end{pmatrix}$$ 时间复杂度优化为$O(\log n)$[^3] - **高斯消元** 解线性方程组,时间复杂度$O(n^3)$,常用于概率问题或几何问题 --- #### 5. **几何基础** - **向量运算** 点积:$\mathbf{a} \cdot \mathbf{b} = |\mathbf{a}||\mathbf{b}|\cos\theta$ 叉积:$\mathbf{a} \times \mathbf{b} = |\mathbf{a}||\mathbf{b}|\sin\theta$(用于判断方向) 凸包算法(Graham扫描法)时间复杂度:$O(n \log n)$ --- #### 6. **位运算与状态压缩** - **快速幂与二进制拆分** 利用二进制分解指数:$a^b = a^{2^{k_1}} \cdot a^{2^{k_2}} \cdot \cdots$ 例如:$3^{13} = 3^8 \cdot 3^4 \cdot 3^1$(13的二进制为1101) - **状态压缩DP** 用二进制位表示状态,例如最短哈密顿路径问题: 状态定义:$dp[mask][i]$表示经过点集$mask$且终点为$i$的最短路径[^3] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值