最最基础的思想与算法

汝爷抽中华,这个劲儿大

知识点

short类型为半个机器字长,int为一个机器字长,4字节能表示最大2 * 10^9
long long int 能表示 9 * 10^18

pi = atan(1.0)*4

%m.nf

函数

  • sort O(nlogn)O(nlogn)
  • isdigit()判断是否是数字
  • lower_bound (first, last, val, cmp) - first; 返回大于等于val的元素的下标
  • upper_bound (first, last, val, cmp) - first; 返回大于val的元素的下标

基础数学

进制转换

请你编一程序实现两种不同进制之间的数据转换

1
2
3
4
5
6
7
8
9
10
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
int main(){
int n, m;
char ouput[maxn], input[maxn];
cin >> n >> input >> m;
cout << itoa(strtol(input, NULL, n), ouput, m);
return 0;
}

高低位交换

与ffff与相当于把ffff对应的位 取出来

1
2
3
4
5
位交换
int main(){
unsigned int x; cin >> x;
cout<<((x & 0x0000ffff) << 16 | (x & 0xffff0000) >> 16) << endl;
}

素数判别与筛法

时间复杂度分别为 O(n1/2) O(nlognlogn)O(n^{1/2}) \ O(nlognlogn)

1
2
3
4
5
6
bool isPrime(a) {  
if (a < 2) return 0;
for (int i = 2; i * i <= a; ++i)
if (a % i) return 0;
return 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int erato(int n) {
int p = 0;
for (int i = 0; i <= n; ++i) is_prime[i] = 1;
is_prime[0] = is_prime[1] = 0;
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
prime[p++] = i; // prime[p]是i,后置自增运算代表当前素数数量
for (int j = i * i; j <= n;
j += i) // 因为从 2 到 i - 1 的倍数我们之前筛过了,这里直接从 i
// 的倍数开始,提高了运行速度
is_prime[j] = 0; //是i的倍数的均不是素数
}
}
return p;
}

公约数

1
2
3
4
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}

公倍数

1
2
3
int lcm(int a,int b){
return a * b / gcd(a, b);//最小公倍数
}

斐波那契

例题: https://www.dotcpp.com/oj/problem1004.html dp思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int n, f[100];
int main(){
f[1] = 1; f[2] = 2; f[3] = 3; f[4] = 4;
while(cin >> n){
if (n == 0) break;
for (int i = 5; i <= n; i++)
f[i] = f[i - 1] + f[i - 3];
cout << f[n] << '\n';
}
return 0;
}

杨辉三角

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<cstdio>
int n,a[21][21];
int main()
{
scanf("%d",&n);//输入
a[1][1]=1;//初始化
for(int i=2;i<=n;i++)for(int j=1;j<=i;j++)a[i][j]=a[i-1][j-1]+a[i-1][j];//进行计算
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)printf("%d ",a[i][j]);//输出
printf("\n");//换行
}
}

闰年判断

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
cin>>n;
cout<< ((n % 4 == 0 && n % 100 != 0) || (n % 400 == 0)) ? 1 : 0;
return 0;
}

STL

string 类

​ 同样是一种容器,以顺序标为结构,元素为字符

​ 成员函数:

  • size()

  • push_back('a')

  • append("ABC")

  • insert(index,times,'a')

  • compare("ABCD") 相等返回0 部分相等返回值大于0

    反转,需要引入algorithm头文件

  • reverse(str.begin(),str.end())

前缀和

一维

b[0]=a[0],  b[i]=b[i1]+a[i]b[0] = a[0] , \ \ b[i] = b[i - 1] + a[i]

字符串

全排列

可以使用nex_permutation来输出全排列,但是首先需要排序
例题 : http://www.51nod.com/Challenge/Problem.html#problemId=1384

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;

int main(){
char num[10];
cin >> num;
int len = strlen(num);
sort(num, num + len);
do{
cout << num << endl;
}while(next_permutation(num, num + len));
return 0;
}

字符串匹配

暴力做法

O(nm)O(nm)

1
2
3
4
5
6
7
8
9
10
std::vector<int> match(char *a, char *b, int n, int m) {
std::vector<int> ans;
for (i = 0; i < n - m + 1; i++) {
for (j = 0; j < m; j++) {
if (a[i + j] != b[j]) break;
}
if (j == m) ans.push_back(i);
}
return ans;
}

KMP算法

字典树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const int maxn = 1000010;
struct tire{
int nex[maxn][26], cnt;
int exist[maxn], tot[maxn];

void insert(string s){
int len = s.size();
int p = 0;
for (int i = 0; i < len; i++){
int c = s[i] - 'a';
if (!nex[p][c]) nex[p][c] = ++cnt;
p = nex[p][c];
}
exist[p] = 1;
}

int find(string s){
int len = s.size();
int p = 0;
for (int i = 0; i < len; i++){
int c = s[i] - 'a';
if (!nex[p][c]) return 0;
p = nex[p][c];
}
return exist[p]++;
}
} dict;

高精度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>

using namespace std;
const int maxn = 2010;

string add(string a, string b) {
string str;
if (a.size() > b.size()) {
string c = a; a = b; b = c;
}
int len = b.size();
for (int i = b.size() - a.size(); i > 0; i--)
a = '0' + a;
int cf = 0, tmp;
for (int i = len - 1; i > -1; i--) {
tmp = a[i] - '0' + b[i] - '0' + cf;
cf = tmp / 10;
tmp = tmp % 10;
str = char(tmp + '0') + str;
}
if (cf != 0) str = char(cf + '0') + str;
return str;
}

string mult(string stra, string strb) {
int a[maxn], b[maxn], c[2 * maxn] = { 0 };
int lena = stra.size(), lenb = strb.size();
for (int i = 1; i <= lena; i++) a[i] = stra[lena - i] - '0';
for (int i = 1; i <= lenb; i++) b[i] = strb[lenb - i] - '0';
for (int i = 1; i <= lena; i++)
for (int j = 1; j <= lenb; j++)
c[i + j - 1] += a[i] * b[j];
for (int i = 1; i < lena + lenb; i++)
if (c[i] > 9) {
c[i + 1] += c[i] / 10;
c[i] = c[i] % 10;
}
int len = lena + lenb;
while (c[len] == 0 && len > 1) len--;
string ans;
for (int i = len; i > 0; i--)
ans.push_back(c[i] + '0');
return ans;
}

int main() {
string a, b;
cout << mult("123", "123");
return 0;
}

数据结构

树状数组

单点修改

1
2
3
4
5
6
void add(int x, int k){
while(x <= n){
c[x] += k;
x += lowbit(x);
}
}

区间求和

1
2
3
4
5
6
7
8
int sum(int x){
int ans = 0;
while (x >= 1){
ans += c[x];
x -= lowbit(x);
}
return ans;
}

差分版本

差分版本中不需要对功能函数进行修改,而需要在添加节点的时候修改

1
2
3
4
5
6
7
typedef long long int ll;
ll last = 0;
for (int i = 1; i <= n; i++){
int value; cin >> value;
add(i, v - last);
last = v;
}

当我们对区间[x,y][x,y]修改的时候,只需要add(x, value); add(y + 1, -value)就行了,而上面的版本是单点修改,这里是区间修改

求和就不需要再减了,直接sum(x)即可

并查集

并查集的重要思想在于,用集合中的一个元素代表集合。一个有趣的比喻,把集合比喻成帮派,而代表元素则是帮主

并查集可以用来判断两个元素是否在同一个集合或者合并两个集合,且效率非常高

初始化

1
2
3
4
int fa[maxn];
void init(int n){
for (int i = 0; i < n; i++) fa[i] = 1;
}

查询

1
int find(int x){ return x == fa[x] ? x : (fa[x] = find(fa[x]));}

合并

1
2
3
void merge(int i, int j){
fa[find(i)] = find(j);
}

暴力求解法

子集生成

以下子集生成都是生成整数0n10\sim n-1 的所有子集,所以遇到实际情况的时候需要做一次映射例如 data[one_of_subsets[0~n-1]]

增量构造法

这个可谓是递归的绝妙之处

1
2
3
4
5
6
7
8
void subset_add(int n, int * a, int cur){
for (int i = 0; i < cur; i++) cout << a[i];
cout << '\n';
int s = cur ? a[cur -1] + 1 : 0;
for (int i = s; i < n; i++){
a[cur] = i;subset_add(n, a, cur + 1);
}
}

位向量法

二进制法

1
2
3
4
5
6
void print_subset(int n,int s)
{
for(int i=0;i<n;i++)
if(s&(1<<i))printf("%d ",i);
printf("\n");
}

搜索算法

BFS

迷宫寻宝

给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格的通道移动。请求出从起点到终点所需的最小步数,题目保证一定有解。( ‘#’, ‘.’, ‘S’, 'G’分别表示墙壁、通道、起点和终点)

这是一道bfs模板例题,通过这道题给出模板与bfs要点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const int maxn = 1000;
array[maxn][maxn]; //一个记录图的数据
step[maxn][maxn]; // 一个记录节点对应的步数

void bfs(){
while(!q.empty()){
int v = q.front(); q.pop(); //从队列取出一个元素
if (q满足结束条件) break;
for (int u = firstNbr(v); ; u = nextNbr(v,u)){ // 遍历v的所有邻居u
if( !vis[u] && match(u) && inside(u)) // 考察u的状态:如果没有访问过且符合条件且u在范围内 则
q.pop(u) //送入队列中
step[u] = step(v) + 1; //步数从v加1
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 6;
struct point
{
int x;
int y;
}point1,point2;

struct info
{
int step;
int px, py;
};

char maze[maxn][maxn];
int N, M;
int sx, sy, gx, gy;
info map[maxn][maxn]; //增加了保存路径的结构体,以便输出路径
vector<point> way;
int dirt[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };

void return_path(int x, int y) {
if (x == 0 && y == 0) return;
else
{
int px = map[x][y].px, py = map[x][y].py;
point p = { py, -px }; way.push_back(p);
return_path(x - px, y - py);
}
}

void print_path() {
reverse(way.begin(), way.end());
for (int i = 0; i < way.size(); i++) {
cout << way[i].x << ',' << way[i].y << '\n';
}
}
void bfs()
{
queue<point> que;
point1 = { sx,sy }; que.push(point1); map[sx][sy] = { 0, 0, 0 };

while (!que.empty())
{
point1 = que.front(); que.pop();
if (point1.x == gx && point1.y == gy) {
return_path(gx, gy); break;
}
for (int i = 0; i < 4; i++)
{
point2.x = point1.x + dirt[i][0]; point2.y = point1.y + dirt[i][1];
if (0 <= point2.x && point2.x < N && 0 <= point2.y && point2.y <= M && maze[point2.x][point2.y] != '#' && map[point2.x][point2.y].step == 0)
{
que.push(point2);
map[point2.x][point2.y].step = map[point1.x][point1.y].step + 1;
map[point2.x][point2.y].px = dirt[i][0]; map[point2.x][point2.y].py = dirt[i][1];
}
}
}
}
int main()
{
cin >> N >> M;

for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
cin >> maze[i][j];

for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
{
if (maze[i][j] == 'S')
{
sx = i; sy = j;
}
if (maze[i][j] == 'G')
{
gx = i; gy = j;
}
}
bfs();
cout << map[gx][gy].step << endl;
print_path();
return 0;
}

DFS

连通块问题

接下来有m行数据,每行数据有n个字符(不包括行结束符)。每个字符代表一个小方块,如果为“*”,则代表没有石油,如果为“@”,则代表有石油,是一个pocket
http://acm.hdu.edu.cn/showproblem.php?pid=1241
这个答案正确但是放到oj上就wa了,不知道为啥…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>
using namespace std;
const int maxn = 1000;
char map[maxn][maxn];
int idm[maxn][maxn];
int n, m;

void dfs(int x, int y, int cur) {
if (x < 0 || x >= m || y < 0 || y >= m) return;
if (idm[x][y] > 0 || map[x][y] != '@') return;
idm[x][y] = cur;
for (int dx = -1; dx <= 1; dx++)
for (int dy = -1; dy <= 1; dy++) {
if (dx != 0 || dy != 0) dfs(x + dx, y + dy, cur);
}
}

int main() {
while (cin >> n >> m) {
if (n == 0 && m == 0) break;
else {
for (int i = 0; i < n; i++)
cin >> map[i];
int count = 0; memset(idm, 0, sizeof(idm));
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (map[i][j] != '*' && idm[i][j] == 0) dfs(i, j, ++count);
}
cout << count << '\n';
}
}
return 0;
}

拓扑排序

给出t个变量,还有m个二元组(u,v),表示u小于v,求所有变量从小到大的排列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const int maxn = 20;
int g[maxn][maxn];
int c[maxn];
int topo[manx];
int t; //t个元

void dfs(int u){
c[u] = -1;
for (int v = 0; v < n; v++)if(g[u][v]){
if (c[v] < 0) return false;
else if (!c[v] && !dfs(v)) return false;
}
c[u] = 1; topo[--t] = u; return true;
}

bool toposort(){
memset(c,0,sizeof(c));
for (int u = 0; u < t; u++) if(!c[u]) if(!dfs(u)) return false; //尝试从每一个点开始排序
return true;
}

欧拉回路

简称一笔画问题,判断存在欧拉回路的充要条件是所有节点出度等于入度

回溯法

素数环

整数1,2,3…n填到一个环中,要求每个整数只填写一次,并且相邻的两个整数之和是一个素数

查了查网上写法大多都不优雅简洁,这种是比较简洁实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
const int maxn = 16;
int isp[2 * maxn];
int a[maxn];
int vis[maxn];
int n = 0;
int is_prime(int n) {
for (int i = 2; i < n; i++) if (n % i == 0) return 0;
return 1;
}

void dfs(int cur) {
a[0] = 1;
if (cur == n && isp[a[0] + a[n - 1]]) {
for (int i = 0; i < n; i++) cout << a[i] << ' ';
cout << '\n';
}
else {
for (int i = 2; i <= n; i++) {
if (!vis[i] && isp[i + a[cur - 1]]) {
a[cur] = i; vis[i] = 1;
dfs(cur + 1);
vis[i] = 0;
}
}
}
}

int main() {
for (int i = 0; i < 2 * maxn; i++)
isp[i] = is_prime(i);
while (cin >> n){
dfs(1);
}
return 0;
}

八皇后

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法
和上一题有异曲同工之妙,也是回溯问题的典型案例,采用递归可以看出代码十分精简.从初二第一次看到这个问题的时候只知道迭代且没有数据结构的知识下,一直都没有解决.但现在看起来也没有多难…
虽然采用回溯法,但是数字较大的时候,效率仍然堪忧,当然这道题也可以采用迭代的算法,加上栈的效果更加哦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <cstring>
using namespace std;

const int maxn = 1000;
int vis[maxn][maxn];
int tot = 0, n;
int result[maxn];

void dfs(int line){
if (line == n) tot++;
else{
for (int i = 0; i < n; i++){ //尝试所有的列
result[line] = i;int ok = 1;
for (int j = 0; j < line; j++) //check 之前的棋子是否冲突 y1 == y2 or y1-x1 == y2-x2 or y1+x1 == y2+x2 则在对角线上或同一列上
if ( result[j] == i || j + result[j] == line + i || j - result[j] == line - i){
ok = 0; break;
}
if (ok) dfs(line + 1);
}

}
}

int main(){
while(cin >> n){
tot = 0;
dfs(0);
cout << tot << '\n';
}
return 0;
}

贪心法

贪心算法主要是取决于策略思想,策略给对了那就对了

策略相关

有 n 个人在一个水龙头前排队接水,假如每个人接水的时间为 T,请编程找出这 n 个人排队的一种顺序,使得 n 个人的平均等待时间最小。

例题: https://www.luogu.com.cn/problem/P1223

其中用到了间接排序,很方面不需要写结构体再排序,此外注意如果记录从1开始,排序的sort参数也要加一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long int ll;
const int maxn = 1e3 + 10;
int n;
ll a[maxn], b[maxn];

bool cmp(int x, int y){
return a[x] < a[y];
}

int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i]; b[i] = i;
}
sort(b + 1, b + n + 1, cmp);
double sum = 0;
for (int i = 1; i <= n; i++){
cout << b[i] << ' ';
sum += (n - i) * a[b[i]];
}
cout << endl;
printf("%.2lf", sum / (n * 1.0));
return 0;
}

区间相关

选择不相交区间

yyy 认为,参加越多的比赛,noip 就能考的越好(假的).所以,他想知道他最多能参加几个比赛。

首先明确一个问题,如果x包含y区间,那么选择x还是y区间呢?答案是明显的,如果选择y区间不仅区间数目没有变,而且还能为其他区间提供空间,那么如果我们吧所有区间按照bi的大小排序,那么我们总是选择最小的bi即可

例题: https://www.luogu.com.cn/problem/P1803

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long int ll;
const int maxn = 1e6 + 10;
int n;

struct block {
int x, y;
}b[maxn];

bool cmp(block l, block r) {
return l.y < r.y;
}

int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> b[i].x >> b[i].y;
sort(b + 1, b + n + 1, cmp);
int pos = 0, ans = 0;

for (int i = 1; i <= n; i++) {
if (pos <= b[i].x) {
pos = b[i].y;
ans++;
}
}
cout << ans;
return 0;
}

区间覆盖问题

删数问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>
using namespace std;

int main(){
string a;
int k;
cin>> a >> k;
if (k >= a.size()) a.erase();
else while(k > 0){
for (int i=0; (i < a.size() - 1) && (a[i] <= a[i + 1]); ++i); //寻找最近下降点,保留当前i,随后逐个删除
a.erase(i, 1);
k--;
}
while(a.size() > 1 && a[0] == '0') a.erase(0, 1);
cout<<a<<endl;
}

背包相关

详见 文章:动态规划-初步

动态规划

记忆化搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
const int maxn = 1010;

int a[maxn][maxn],d[maxn][maxn] = {-1}, vis[maxn][maxn] = {0};
int n;
int solve(int i, int j){
if (vis[i][j] == 1) return d[i][j];
vis[i][j] = 1;
return d[i][j] = a[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
}
int main(){
std::ios::sync_with_stdio(false);
cin >> n;
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
cin >> a[i][j];
cout << solve(0,0);

return 0;
}

记忆搜索 + DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <algorithm>
const int maxn = 10000;
using namespace std;
int r, c;
int d[maxn][maxn], a[maxn][maxn], vis[maxn][maxn];
int dict[4][2] = { {0,1}, {0,-1}, {-1,0}, {1,0} };
int dfs(int x, int y) {
if (vis[x][y] != 0) return d[x][y];
vis[x][y] = 1;
int sum = d[x][y];
for (int i = 0; i < 4; i++) {
int dx, dy;
dx = x + dict[i][0]; dy = y + dict[i][1];
if (dx >= 0 && dx < r && dy >= 0 && dy < c && a[x][y] > a[dx][dy])
sum = max(dfs(dx, dy) + d[x][y], sum);
}
return d[x][y] = sum;
}
int main() {
cin >> r >> c;
int ans = 0;
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
d[i][j] = 1;
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
cin >> a[i][j];

for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
ans = max(ans, dfs(i, j));
cout << ans;
return 0;
}

二分

二分查找 O(logn)O(logn)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int binary_search(int start, int end, int key) {
int ret = -1; // 未搜索到数据返回-1下标
int mid;
while (start <= end) {
mid = start + ((end - start) >> 1); //直接平均可能会溢出,所以用这个算法
if (arr[mid] < key)
start = mid + 1;
else if (arr[mid] > key)
end = mid - 1;
else {
ret = mid;
break;
}
}
return ret ; // 单一出口
}

二分答案

例题 : https://www.luogu.com.cn/problem/P1873

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

using namespace std;
const int maxn = 1e6 + 10;
const int hight = 1e9 + 1;
typedef long long int ll;

int n, m;
ll a[maxn];

bool check(int mid){
ll sum = 0;
for (int i = 1; i <= n; i++)
if (a[i] > mid)
sum += a[i] - mid;
return sum >= m;

}
int main(){
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
ll l = 0, r = hight, mid;
while(l + 1 < r){
mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
cout << l;
return 0;
}

评论




Blog content follows the Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License

loading...loading... , total visits times