CSP知识点(10月2日集训)

1. 基础知识

1.1 引用(捆绑法)

#include<cstdio>
int a[20];
int main () {
	int &x = a[1];
	x = 9;
	printf("%d", a[1]); //输出9 
	return 0;
}

1.2 EOF

(1) ctrl+z实现

#include<bits/stdc++.h>
using namespace std;
int main () {
	int n;
	while(scanf("%d", &n)) printf("%d\n", n); //按ctrl+z作为文件结束符(EOF) 
	return 0;
}

(2) -1实现

#include<bits/stdc++.h>
using namespace std;
int main () {
	int n;
	while(scanf("%d", &n) != -1) printf("%d\n", n); //EOF即为-1
	return 0;
}

(3) 按位取反实现

#include<bits/stdc++.h>
using namespace std;
int main () {
	int n;
	while(scanf("%d", &n) != -1) printf("%d\n", n); //-1的二进制补码为全1,按位取反后为全0
	return 0;
}

1.3 快读函数

快读函数返回的数据类型可以根据需要自行修改。

#include<bits/stdc++.h>
using namespace std;
int n, o, i;
int read() {
	int ans = 0;
	bool neg = false;
	char c = getchar();
	while(c != '-' && !isdigit(c)) c = getchar();
	if(c == '-') neg = true, c = getchar();
	while(isdigit(c)) ans = 10*ans + c-'0', c = getchar(); 
	return neg ? -ans : ans;
} 
int main () {
	n = read(), o = read(), i = read();
	printf("%d %d %d", n, o, i);
	return 0;
}

1.4 格式化输入

(1)例如输入YYYY-MM-DD, 就可以用scanf中的格式化输入进行输入。

#include<bits/stdc++.h>
using namespace std;
int y, m, d;
int main () {
	scanf("%d-%d-%d", &y, &m, &d);
	printf("%d %d %d", y, m, d);
	return 0;
}

(2)

#include<bits/stdc++.h>
using namespace std;
int main () {
	for(int i = 1;i <= 5;++i)
		for(int j = 1;j <= 5;++j)
			printf("%d%c", i+j, " \n"[j==5]); //如果j是5,就换行,否则打空格 
	return 0;
}

1.5 字符串输入

gets不安全,fgets又会把回车录进去,最好的办法还是getline。
getline函数很简单,第一个参数是要输入的字符串,第二个参数为最多输入的字符数。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
char s[N];
int main () {
	cin.getline(s, N);
	cout << s;
	return 0;
}

1.6 数据类型

int: -2147483648~2147483647
unsigned:无符号数
当int与unsigned int比较时,需要先把int转化成unsigned int比较。

2. 算法

2.1 快速幂

1.递归写法

#include<bits/stdc++.h>
using namespace std;
int qpow(int n, int m, int mod) {
	if(m == 0) return 1;
	if(n&1) return n*qpow(n, m-1, mod)%mod;
	int t = qpow(n, m/2, mod);
	return t*t % mod;
}
int main () {
	int n, m, mod;
	scanf("%d%d%d", &n, &m, &mod);
	printf("%d", qpow(n, m, mod));
	return 0;
}

2.while写法


#include<bits/stdc++.h>
using namespace std;
int n, m, mod;
int qpow(int n, int m, int mod) {
	long long ans = 1;
	while(m) {
		if(m&1) ans = ans*n % mod;
		n = n*n % mod, m >>= 1;
	}
	return ans;
}
int main () {
	scanf("%d%d%d", &n, &m, &mod);
	printf("%d", qpow(n, m, mod));
	return 0;
}

2.2 常用函数

strcasecmp(s1, s2): 忽略大小写比较s1和s2的大小

2.3 快速排序

#include<bits/stdc++.h>
using namespace std;
const int N	 = 1e5 + 7;
int a[N], n;
void qsort(int lo, int hi) {
	int i = lo, j = hi, mid = a[(lo+hi)>>1];
	while(i <= j) {
		while(a[i] < mid) ++i;
		while(a[j] > mid) --j;
		if(i <= j) swap(a[i++], a[j--]);
	}
	if(lo < j) qsort(lo, j);
	if(i < hi) qsort(i, hi); 
}
int main () {
	scanf("%d", &n);
	for(int i = 1;i <= n;++i) scanf("%d", a+i);
	qsort(1, n);
	for(int i = 1;i <= n;++i) printf("%d ", a[i]);
	return 0;
}

2.4 深搜

1. 求和

先举一个大聪明都会的题,就是求1+2+……+n的值。

#include<bits/stdc++.h>
using namespace std;
int dfs(int k) {
	if(k == 1) return 1;
	return dfs(k-1) + k;
}
int k;
int main () {
	scanf("%d", &k);
	printf("%d", dfs(k));
	return 0;
}

2.皇后问题

1.四皇后

(1) 循环写法

#include<bits/stdc++.h>
#define f(i) for(int i = 1;i <= 4;++i)
using namespace std;
bool col[10], sl[20], an[20]; //slash
int cnt, ans[5];
void print() {
	printf("%d %d %d %d\n", ans[1], ans[2], ans[3], ans[4]);
}
int main () {
	f(i1) {
		col[i1] = sl[i1+2] = an[1+i1] = true, ans[1] = i1;
		f(i2) {
			if(col[i2] || sl[i2+1] || an[2+i2]) continue;
			col[i2] = sl[i2+1] = an[2+i2] = true, ans[2] = i2;
			f(i3) {
				if(col[i3] || sl[i3] || an[3+i3]) continue;
				col[i3] = sl[i3] = an[3+i3] = true, ans[3] = i3;
				f(i4) {
					if(col[i4] || sl[i4-4+3] || an[4+i4]) continue;
					ans[4] = i4;
					print();
				}
				col[i3] = sl[i3] = an[3+i3] = false;
			}
			col[i2] = sl[i2+1] = an[2+i2] = false;
		}
		col[i1] =  sl[i1+2] = an[1+i1] = false;
	}
	printf("%d", cnt);
	return 0;
}
2. 8皇后

由四皇后可以顺理成章地过渡到八皇后。

#include<bits/stdc++.h>
using namespace std;
bool col[10], sl[20], an[20]; //slash
int cnt, ans[10];
void print() {
	for(int i = 1;i <= 8;++i) printf("%d ", ans[i]);
	puts("");
}
void dfs(int k) {
	if(k == 9) {
		print();
		return;
	}
	for(int i = 1;i <= 8;++i) {
		if(col[i] || sl[k-i+7] || an[k+i]) continue;
		col[i] = sl[k-i+7] = an[k+i] = true, ans[k] = i;
		dfs(k+1);
		col[i] = sl[k-i+7] = an[k+i] = false;
	}
}
int main () {
	dfs(1);
	return 0;
}
3.n皇后

如果你不服气,说4皇后和8皇后都可以用循环解决,那么请试试n皇后。
你还可以吗?

#include<bits/stdc++.h>
using namespace std;
bool col[20], sl[40], an[40]; //slash
int cnt, ans[20], n;
void print() {
	for(int i = 1;i <= n;++i) printf("%d ", ans[i]);
	puts("");
}
void dfs(int k) {
	if(k == n+1) {
		print();
		return;
	}
	for(int i = 1;i <= n;++i) {
		if(col[i] || sl[k-i+n-1] || an[k+i]) continue;
		col[i] = sl[k-i+n-1] = an[k+i] = true, ans[k] = i;
		dfs(k+1);
		col[i] = sl[k-i+n-1] = an[k+i] = false;
	}
}
int main () {
	scanf("%d", &n);
	dfs(1);
	return 0;
}

3.枚举集合

1.基础版

输入 n,问从 1,2,3,…,n-1,n中选出若干个数使得他们的和为 n,有多少种方案。每一个数最多只能选一次。(1 <= n <= 16)

#include <cstdio>
int n, a[17], vis[17], cnt, sum;
void dfs(int t) {
    if (sum == n) {
        ++cnt;
        return;
    }

    for (int i = 1; i <= n - sum; ++i) {
        if (!vis[i] && i > a[t - 1]) {
            vis[i] = 1;
            a[t] = i;
            sum += i;
            dfs(t + 1);
            sum -= i;
            vis[i] = 0;
        }
    }
}
int main() {
    freopen("enum1.in", "r", stdin);
    freopen("enum1.out", "w", stdout);
    scanf("%d", &n);
    dfs(1);
    printf("%d", cnt);
    return 0;
}
2.升级版

其实非常简单,只不过把vis数组改成int型的就可以了。

#include <cstdio>
int n, a[16], vis[16], cnt, sum;
void dfs(int t) {
    if (sum == n) {
        ++cnt;
        return;
    }

    for (int i = 1; i <= n - sum; ++i) {
        if (vis[i] < 3 && i >= a[t - 1]) {
            ++vis[i];
            a[t] = i;
            sum += i;
            dfs(t + 1);
            sum -= i;
            --vis[i];
        }
    }
}
int main() {
    freopen("enum2.in", "r", stdin);
    freopen("enum2.out", "w", stdout);
    scanf("%d", &n);
    dfs(1);
    printf("%d", cnt);
    return 0;
}

3.数据结构

3.1 队列

1.blah数集

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
typedef long long ll;
int a, n;
int main () {
	while(~scanf("%d%d", &a, &n)) {
		queue<ll> que2, que3;
		que2.push(2*a+1);
		que3.push(3*a+1);
		for(int i = 1;i < n;++i) {
			ll minn = min(que2.front(), que3.front());
			a = minn;
			que2.push(2*a+1);
			que3.push(3*a+1);
			if(minn == que2.front()) que2.pop();
			if(minn == que3.front()) que3.pop();
		}
		printf("%d\n", a);
	}
	return 0;
}

3.2 并查集(从入门到放弃

1.模板

#include<bits/stdc++.h>
using namespace std;
int fa[10005], n, m;
int find(int x) {
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
void hb(int x, int y) {
	fa[find(x)] = find(y);
	return;
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= n;++i) fa[i] = i;
	for(int i = 1, z, x, y;i <= m;++i) {
		scanf("%d%d%d", &z, &x, &y);
		if(z == 1) hb(x, y);
		else 
			if(find(fa[x]) == find(fa[y])) puts("Y");
			else puts("N");
	}
    return 0;   
}

2.团伙(BOI2003)

#include<bits/stdc++.h>
using namespace std;
int s,n,m,a,b,f[2500];
char ch;
int find(int x){
    if(f[x]!=x)f[x]=find(f[x]);//查找+路径压缩,如果没有祖先就回溯
    return f[x];
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=2*n;i++){
        f[i]=i;//初始化,千万不能漏
    }
    for(int i=1;i<=m;i++){
        cin>>ch>>a>>b;
        if(ch=='F'){
            f[find(a)]=find(b);//合并
        }else{
            f[find(a+n)]=find(b);
            f[find(b+n)]=find(a);//反集合并
        }
    }
    for(int i=1;i<=n;i++){
        if(f[i]==i)s++;
    }
    cout<<s;//祖先数就是团伙数
}

3.食物链(个人认为最恶心)
这一题,一句话总结就是:读题时很好玩,做题时一脸懵。

//留给大家自己做

3.3 堆

1.down函数

void down(int x) {
	int cur = x<<1, u = a[x];
	while(cur <= n) {
		if(cur<n && a[cur+1]>a[cur]) ++cur;
		if(a[cur] <= u) break;
		a[x] = a[cur], x = cur, cur <<= 1;
	}
	a[cur>>1] = u;
}

2.堆排序

注意:用小根堆排序是从大到小,用大根堆排序是从小到大。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int a[N], n;
void down(int x, int n) {
	int cur = x<<1, u = a[x];
	while(cur <= n) {
		if(cur<n && a[cur+1]>a[cur]) ++cur;
		if(a[cur] <= u) break;
		a[x] = a[cur], x = cur, cur <<= 1;
	}
	a[cur>>1] = u;
}
int main() {
	scanf("%d", &n);
	for(int i = 1;i <= n;++i) scanf("%d", a+i);
	for(int i = n>>1; i;--i) down(i, n);
	for(int i = n;i > 1;--i) {
		swap(a[i], a[1]);
		down(1, i-1);
	}
	for(int i = 1;i <= n;++i) printf("%d ", a[i]);
    return 0;
}

3.3 合并果子

(1)手写堆版本

#include<bits/stdc++.h>
using namespace std;
const int N = 107;
int a[N], m, n;
void down(int x, int n) {
	int cur = x<<1, u = a[x];
	while(cur <= n) {
		if(cur<n && a[cur+1]<a[cur]) ++cur;
		if(a[cur] >= u) break;
		a[x] = a[cur], x = cur, cur <<= 1;
	}
	a[x] = u;
}
inline int top () {return a[1];}
void pop() {a[1] = a[n--]; down(1, n);}
void push(int u) {
	a[++n] = u;
	int cur = n>>1, x = n;
	while(cur) {
		if(a[cur] <= u) break;
		a[x] = a[cur], x = cur, cur >>= 1;
	}
	a[x] = u;
}
int main(){
	int sum = 0;
	scanf("%d", &m);
	for(int i = 1, x;i <= m;++i) {
		scanf("%d", &x);
		push(x);
	}
	while(--m) {
		int x = top(); pop();
		int y = top(); pop();
		sum += x+y;
		push(x+y);
	}
	printf("%d", sum);
    return 0;
}

(2)STL版本

#include<bits/stdc++.h>
using namespace std;
int n, x, ans;
priority_queue<int, vector<int>, greater<int> >q;
int main(){
	cin >> n;
	for(int i=1;i<=n;i++) cin>>x, q.push(x);
	while(q.size() >= 2){
		int a = q.top(); q.pop();
		int b = q.top(); q.pop();
		ans += a+b;
		q.push(a+b);
	}
	cout << ans;
	return 0;
}

4.结语

此博客为本人集训13小时的收获(8:00 ~ 21:00),明天再见!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
CSP(信息学奥林匹克竞赛)复赛的知识点非常广泛,涵盖了计算机科学和算法设计的各个领域。以下是一些常见的CSP复赛知识点: 1. 数据结构:熟悉数组、链表、栈、队列、树、图等数据结构的原理和应用。能够快速选择和实现合适的数据结构来解决问题。 2. 算法设计与分析:掌握基本的算法设计方法,如贪心算法、分治算法、动态规划算法、回溯算法等。了解算法的时间复杂度和空间复杂度分析方法。 3. 图论:熟悉图的基本概念和常见算法,如最短路径算法(Dijkstra算法、Floyd-Warshall算法等)、最小生成树算法(Prim算法、Kruskal算法等)、网络流算法(最大流最小割定理、Ford-Fulkerson方法等)。 4. 字符串处理:熟练掌握字符串的基本操作,并能够应用字符串匹配算法(KMP算法、Boyer-Moore算法等)解决相关问题。 5. 动态规划:了解动态规划的基本思想和应用场景,能够分析并设计动态规划算法来解决问题。 6. 排序与查找:掌握常见的排序算法(如冒泡排序、快速排序、归并排序等)和查找算法(如二分查找、哈希表等)的原理和应用场景。 7. 数学知识:了解离散数学、概率论和组合数学等数学知识,能够将数学方法应用到算法设计。 8. 算法竞赛技巧:熟悉算法竞赛常见的问题解题技巧,如递归、分治、二分、模拟、枚举、贪心、搜索、优化等。 在CSP复赛,不仅需要掌握上述知识点,还需要具备解决难题的思维能力、编程实现能力以及分析和优化算法的能力。通过不断的练习和实践,可以提高自己的算法和编程水平,取得好成绩。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

庄荣涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值