二分法练习题总结(不容错过的经典好题!!!)

A题

来源:http://codeforces.com/problemset/problem/4/C

A new e-mail service “Berlandesk” is going to be opened in Berland in the near future. The site administration wants to launch their project as soon as possible, that’s why they ask you to help. You’re suggested to implement the prototype of site registration system. The system should work on the following principle.

Each time a new user wants to register, he sends to the system a request with his name. If such a name does not exist in the system database, it is inserted into the database, and the user gets the response OK, confirming the successful registration. If the name already exists in the system database, the system makes up a new user name, sends it to the user as a prompt and also inserts the prompt into the database. The new name is formed by the following rule. Numbers, starting with 1, are appended one after another to name (name1, name2, …), among these numbers the least i is found so that name i does not yet exist in the database.

Input
The first line contains number n (1 ≤ n ≤ 105). The following n lines contain the requests to the system. Each request is a non-empty line, and consists of not more than 32 characters, which are all lowercase Latin letters.

Output
Print n lines, which are system responses to the requests: OK in case of successful registration, or a prompt with a new name, if the requested name is already taken.

Examples
Input
4
abacaba
acaba
abacaba
acab

Output
OK
OK
abacaba1
OK

Input
6
first
first
second
second
third
third

Output
OK
first1
OK
second1
OK
third1

题意:
题意不算难懂,就是一个用户注册系统,如果输入的用户名没出现过就输出“OK”,如果出现过 i 次,就在用户名的后边添上数字 i

思路:
虽然这是二分的练习题,但是我真没想出来咋用二分的方法做,不符合二分的特点啊…,暴力写了一个,结果超时了

暴力枚举 】(超时)

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
string a[N];
int main()
{
   
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++)
	{
   
		int k = 0;
		for (int j = 1; j < i; j++)
			if (a[i] == a[j])
				k++;
		if (k == 0)
			cout << "OK" << endl;
		else
			cout << a[i] << k << endl;
	}
	return 0;
}

然后就从别的角度看这个题,结果发现发现用STL的中的map就能非常简单的解决这个问题。

【map】(AC)

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{
   
	map<string, int> m;
	string s;
	int n;
	cin >> n;
	while (n--)
	{
   
		cin >> s;
		m[s]++;
		if (m[s] > 1)
			cout << s << m[s] - 1 << endl;
		else
			cout << "OK" << endl;
	}
	return 0;
}

B题

来源:http://codeforces.com/contest/230/problem/C

You are given a table consisting of n rows and m columns. Each cell of the table contains a number, 0 or 1. In one move we can choose some row of the table and cyclically shift its values either one cell to the left, or one cell to the right.

To cyclically shift a table row one cell to the right means to move the value of each cell, except for the last one, to the right neighboring cell, and to move the value of the last cell to the first cell. A cyclical shift of a row to the left is performed similarly, but in the other direction. For example, if we cyclically shift a row “00110” one cell to the right, we get a row “00011”, but if we shift a row “00110” one cell to the left, we get a row “01100”.

Determine the minimum number of moves needed to make some table column consist only of numbers 1.

Input
The first line contains two space-separated integers: n (1 ≤ n ≤ 100) — the number of rows in the table and m (1 ≤ m ≤ 104) — the number of columns in the table. Then n lines follow, each of them contains m characters “0” or “1”: the j-th character of the i-th line describes the contents of the cell in the i-th row and in the j-th column of the table.

It is guaranteed that the description of the table contains no other characters besides “0” and “1”.

Output
Print a single number: the minimum number of moves needed to get only numbers 1 in some column of the table. If this is impossible, print -1.

Examples
Input
3 6
101010
000100
100000
Output
3

Input
2 3
111
000
Output
-1

Note
In the first sample one way to achieve the goal with the least number of moves is as follows: cyclically shift the second row to the right once, then shift the third row to the left twice. Then the table column before the last one will contain only 1s.

In the second sample one can’t shift the rows to get a column containing only 1s.

题意:
给你一个N*M的表格,每个格子里的数字为0或1,可以选中某一行进行向左或者向右移动。移动规则:

  • 将某一行向右移动一个单元格意味着将每个单元格(最后一个单元格除外)的值移动到右边相邻的单元格,并将最后一个单元格的值移动到第一个单元格。
  • 行向左的移动的执行方式类似,但方向相反。

问最少需要多少步,可以将某一列都变成1。

思路:
这题也是这样,虽然是二分专场,但是还是不知道哪里要用二分…
对于每列计算把每一行中与此列最近的1移到此列的距离之和,然后取得最小值。
当然最近的1必然出现在以此列为中心线的左边或者右边(当然也包括在中心线上的)。当中心线靠右,写后面没有1了,那么它右边的1就应该是此行中最左边的1(移动就是一个环),同样当中心线靠左,且其左边没有1了,那么此时应当纳入计算的就应该是此行中最右边的那个一,我们就可以在最左边和最右边加上额外的两个1。
代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
int main()
{
   
    int n, m;
    scanf("%d%d", &n, &m);
    string a;
    int sum[N];
    memset(sum, 0, sizeof(sum));
    int ans = 0x3f3f3f3f;
    int tmp[N];
    int flag = 0;
    for (int i = 0; i < n; i++)
    {
   
        cin >> a;
        if (flag) 
            continue;
        int s = 1;
        for (int j = 0; j < a.size(); j++)
        {
   
            if (a[j] == '1')
                tmp[s++] = j;
        }
        if (s == 1)//此行中没有一
        {
   
            flag = 1;
            continue;
        }
        tmp[0] = tmp[s - 1] - m;//在左边加上最右边的那个一
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值