CSP知识点
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),明天再见!