noip知识点(转载)

root 站长 2019-10-10 11:17:52 2019-11-02 9:45:20 2

1、模拟算法(暴力枚举),按照题目的要求,题目怎么说就怎么做,保证时间和正确性即可。
2、搜索与回溯,主要的是DFS(深度优先搜索)和BFS(宽度优先搜索),基本没有直接的暴力搜索。一般是记忆化搜索加剪枝,普及组第三题难度。
3、简单操作:如筛法、前缀和、快速幂、高精度、辗转相除法等,掌握全面即可应对大部分处理数据上的问题。
4、队列(单调队列)、栈、堆、链表等基础数据结构。
5、简单二分和分治(快速排序,归并排序)。
6、贪心,要保证贪心的正确性,如果无法证明也可以用来骗分。
7、数学知识、公式计算,要点在于公式的化简与变形,经过反复操作后也许就能得出重要结论。
8、简单的动态规划,容易推出状态转移方程,要注意初值与计算边界条件。
9、字符串基本操作,插入、删除、查找等。
10、经典例题变形加深:八皇后、马的走法、背包问题等。

————————————————
版权声明:本文为CSDN博主「zsjzliziyang」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 摘自该文章,原文链接:https://blog.csdn.net/zsjzliziyang/article/details/81915298

1、 简单搜索

for (int i = 1; i <= n; i ++ )
{
    //...可能存在多重循环
    if ()  // 满足条件
    {

    }
}

2、DFS模板

dfs(int u) // 简单版
{
    if(找到了||走不下去了)
    {
        return;

    }
    开始下一个情况(dfs(u+1));

} 

dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  

    }  
}

链接:https://www.acwing.com/blog/content/461/

3、试除法求质数

bool is_prime(int x)
{
	if (x < 2) return false;
	for (int i = 2; i <= x / i; i ++ )
		if (x % i == 0) 
			return false;
	
	return true;
}

4、朴素法求素数(筛选法)

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i; j <= n; j += i)
            st[j] = true;
    

5、线性筛选法(算法速度更快)

void get_prime(int x)  //st[x]==0表示质数 
{
	for (int i = 2; i <= n; i ++ )
	{
		if (!st[i]) prime[cnt++] = i;
		for (int j = 0; prime[j] <= n / i; j ++)
			st[prime[j]*i] = true;
			if (i % prime[j] == 0) break;
	}
}

6、一维前缀和

for (int i = 1; i <= n; i ++ )  //s表示前缀和数组, a表示原数组
    s[i] = s[i-1] + a[i];

7、二维前缀和

for (int i = 1; i <= n; i ++ )
    for (int j = 1; j <= m; j ++ )
        s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + s[i][j];
//S[i, j] = 第i行j列格子左上部分所有元素的和
//以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

8、高精度加法

// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t) C.push_back(t);
    return C;
}

9、高精度乘法

// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

10、高精度除法(除数为低精度)

// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

11、快速幂

int qmi(int m, int k, int p)
{
	int res = 1 % p,t = m;
	while (k)
	{
		if (k&1) res = res * t % p; // k&1:当k为奇数时,二进制最后一位肯定为1,1&1=1
		t = t * t % p;
		k >>= 1; //k = k >> 1, >> 右移运算符, >>1表示右移一位(0010变成0001),实际上就是除以2 
	}
	return res; 
}

12、辗转相除法

int gcd(int a, int b)
{
    if (b == 0) return a;
    return gcd(b, a % b);
}
{{ vote && vote.total.up }}

共 1 条回复

root 站长

本篇文档中的大部分算法来自 yxc, 链接:https://www.acwing.com