概述
1.位运算
没啥特别重要的东西,只需要知道有符号的整数是用补码来存的,对补码的每一位取反,则数值上 变成-1.
好题:求 (a^b) 对p取模的值,其中(1≤a,b,p≤10^{18})
分析:将 (a^b) 看作b个a相加. b太大怎么办?类似快速幂优化即可.
2.二分and三分
主要用于求特定的答案,即这个答案是能够求出来的,而不是问是否存在,有多少个之类的…… 三分法在使用时需要注意:如果在函数中存在一段值相等的部分,三分法就不再适用,事实上出现这种情况也有解决的方法,如果最后确定了左端点l和右端点r,从l到r枚举一遍所有点判断一下答案即可.
3.平均数问题
如果解题中出现了n个数的平均数T,将这n个数都减去T,以后与0比较即可. 比如要判断一个区间内的数的平均数是否大于x,那么将这n个数都减去x,然后看操作之后的数的和是否大于0即可.
4.中位数问题
如何求中位数?对顶堆!
经典模型:货仓选址问题.
上面两个都是书上涉及到的比较简单的处理方法,有些复杂的问题可能会用到减去偏移量,与中位数比较等方法.
减去偏移量这个方法会在以后提到,与中位数比较则是常用的判定中位数是否存在的一种方法. 二分出中位数x,将比二分出的数大的数标为1,小的数标为-1,求序列的最大连续子段和,若大于0,则x可以是原序列的中位数.接着(l = mid + 1),继续二分.
5.逆序对
归并排序和树状数组都可以求. 一个比较强大的应用是n*m数码的有解性判定.
(N×N)的棋盘,N为奇数时,与八数码问题相同。逆序奇偶同性可互达.
(N)为偶数时,空格每上下移动一次,奇偶性改变。称空格位置所在的行到目标空格所在的行步数为空格的距离(不计左右距离),若两个状态的可相互到达,则有两个状态的逆序奇偶性相同且空格距离为偶数,或者,逆序奇偶性不同且空格距离为奇数数。否则不能。
6.倍增
用来加速枚举,替代二分.
有些题目可以二分,但是在一些极端数据下,二分不如枚举快,这时就可以用倍增来加速枚举,替代二分.举个例子:
给定一个整数T,求出最大的k,满足(Σa_i≤T(1≤i≤k)), 如果T特别小,序列特别长,那么二分就要一步一步缩回来,而倍增则可以从起点一下子找到答案.
7.贪心
收益与代价问题,问题规模一般很大,时间不足以支持dp.
基本策略:在收益最大的前提下让代价尽量最小. 一般涉及到排序,采取决策包容性大的方式排序, 第i次选择时尽量选当前能选到,下一次不一定能选到的.
8.习题
https://ac.nowcoder.com/acm/contest/1004
poj2965 The Pilots Brothers’ refrigerator
枚举 / 位运算 / 搜索
https://www.cnblogs.com/RioTian/p/13461765.html
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main() {
char s[5][5];
int mark[5][5];
int x[20], y[20];
memset(mark, 0, sizeof(mark));
for (int i = 0; i < 4; i++) cin >> s[i];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (s[i][j] == '+') {
mark[i][j] = !mark[i][j];//下面的操作中,i,j这个位置翻转了操作了两次,等于没操作,所以上边这里再操作一次,这样让这个位置 也被操作了
for (int k = 0; k < 4; k++) {
mark[i][k] = !mark[i][k];
mark[k][j] = !mark[k][j];
}
}
}
}
int ans = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (mark[i][j]) {
x[ans] = i + 1;
y[ans] = j + 1;
ans++;
}
}
}
printf("%dn", ans);
for (int i = 0; i < ans; i++) printf("%d %dn", x[i], y[i]);
return 0;
}
poj2083 Fractal
递归 / 分形
#include<iostream>
using namespace std;
const int N=749;
int n;
char a[N][N];
void solve(int n,int x,int y){
if(n==1)a[x][y]='X';
else
if(n>1){
int num=1;
for(int i=2;i<n;i++)
num*=3;
solve(n-1,x,y);
solve(n-1,x,y+num*2);
solve(n-1,x+num,y+num);
solve(n-1,x+num*2,y);
solve(n-1,x+num*2,y+num*2);
}
}
int main(){
while(cin>>n&&n!=-1){
int num=1;
for(int i=1;i<n;i++)
num*=3;
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
a[i][j]=' ';
a[i][num]='