目录
4. 买房
在一条街上有n幢房子,标号从1到n,两个在标号上相差为1的房子视为相邻,这些房子中有k幢房子已有住户。
现你准备搬入这条街,你能搬入一幢房子的条件是这幢房子没有人住在里面,与此同时由于你非常热爱与邻居进行交流,故而你需要你所入住的房子两边上都有住户。
现要你求最小的可能符合要求的房子数,以及最大的可能符合要求的房子数。
Note: 就样例来说,#代表已有住户,-代表空位,这种情况(###---),没有满足条件的房子,为最小,故输出0
最大的情况为(#-#-#-),此种情况有二个位置满足条件,为最大,故输出2
输入描述:
输入的一行为测试用例数t(1 <= t <= 200000), 接下来t行,每行含两个整数n和k,(1 <= n <= 1,000,000,000,0 <= k <= n)
输出描述:
对于每个用例输出最小的可能数以及最大的可能数
输入例子1:
6 1 0 1 1 2 0 2 1 2 2 6 4
输出例子1:
0 0 0 0 0 0 0 0 0 0 0 2
思路:最小的可能数当然是1,接下来讨论最大的可能数,n个住户可以夹出n-1个符合条件的空房子,这里会有两种情况,当剩下的空房子小于n-1时,那最大的可能数就是剩下的空房子数了,当剩下的空房子数大于n-1时,那最大的可能数就是n-1了,因为n个住户只能夹出这么多的可能性。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int num, N, M;
vector<vector<int>> data, data1;
vector<int> data_tmp;
vector<vector<int>> result;
int tmp, res = 0;
int remain = 0;
cin>>num;
for (int i=0;i<num;i++)
{
cin>>N>>M;
data_tmp.push_back(N);
data_tmp.push_back(M);
data.push_back(data_tmp);
data_tmp.clear();
}
for (int i=0; i<num; i++)
{
if (data[i][1] <= 1) //没有住户,当然最大的可能性就是0了
{
data_tmp.push_back(0);
data_tmp.push_back(0);
result.push_back(data_tmp);
data_tmp.clear();
continue;
}
remain = data[i][0] - data[i][1]; //除了住户,剩下的空房子数
if (remain <= data[i][1] - 1 && remain >= 0) //当剩下的空房子小于住户数减1时
{
res = remain;
}else{
res = data[i][1] - 1; //当剩下的空房子大于住户数减1时
}
data_tmp.push_back(0);
data_tmp.push_back(res);
result.push_back(data_tmp);
data_tmp.clear();
}
for (int i=0;i<result.size();i++)
{
cout<<result[i][0]<<" "<<result[i][1]<<endl;
}
return 0;
}
5. 香槟塔
节日到啦,牛牛和妞妞邀请了好多客人来家里做客。
他们摆出了一座高高的香槟塔,牛牛负责听妞妞指挥,往香槟塔里倒香槟。
香槟塔有个很优雅的视觉效果就是如果这一层的香槟满了,就会从边缘处往下一层流去。
妞妞会发出两种指令,指令一是往第x层塔内倒体积为v的香槟,指令二是询问第k层塔香槟的体积为多少。
告诉你香槟塔每层香槟塔的初始容量,你能帮牛牛快速回答妞妞的询问吗?
输入描述:
第一行为两个整数n,m。表示香槟塔的总层数和指令条数。 第二行为n个整数ai,表示每层香槟塔的初始容量。
第三行到第2+m行有两种输入,一种输入是“2 x v”表示往第x层倒入体积为v的香槟;另一种输入是“1 k”表示询问第k层当前有多少香槟。
1 <= n, m <= 1000。
1 <= n ,m <= 200000,1 <= ai ,v <= 1000000000。
输出描述:
对于每个询问,输出一个整数,表示第k层香槟的容量。
输入例子1:
1 2 8 2 1 9 1 1
输出例子1:
8
输入例子2:
5 4 1 2 2 10 1 1 3 2 2 5 2 4 3 1 4
输出例子2:
0 4
思路:按照题目要求一步一步来,香槟从上往下流
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int high, commandNum;
vector<int> initCap, cap, res, commandTmp;
vector<vector<int>> command;
int tmp, M, N;
cin>>high>>commandNum;
for (int i=0;i<high;i++)
{
cin>>tmp;
initCap.push_back(tmp);
cap.push_back(0);
}
for (int i=0; i<commandNum; i++)
{
cin>>tmp;
if (tmp == 1) //查询时
{
cin>>tmp; //此时tmp为查询的层数
if (tmp-1 >=0 && tmp-1 < cap.size())
{
res.push_back(cap[tmp-1]);
}
}else{
cin>>N>>M;
while (N-1 < cap.size() && M > 0) //从上往下流,到最后一层或流不到最后一层就没了
{
if (M >= initCap[N-1] - cap[N-1]) //倒入的总量大于当前层的余量
{
M = M - (initCap[N-1] - cap[N-1]); //还剩多少往下流
cap[N-1] = initCap[N-1]; //当前层满
N++; //层数加1
}else{ //倒入的总量小于当前层的余量
cap[N-1] += M; //全部倒入当前层,那当前层的香槟量
M = 0; //倒完
}
}
}
}
for (int i=0;i<res.size();i++)
{
cout<<res[i]<<endl;
}
return 0;
}
6. 社团主席选举
随着又一届学生的毕业,社团主席换届选举即将进行。
一共有n个投票者和m个候选人,小易知道每一个投票者的投票对象。但是,如果小易给某个投票者一些糖果,那么这个投票者就会改变他的意向,小易让他投给谁,他就会投给谁。
由于小易特别看好这些候选人中的某一个大神,这个人的编号是1,所以小易希望能尽自己的微薄之力让他当选主席,但是小易的糖果数量有限,所以请你帮他计算,最少需要花多少糖果让1号候选人当选。某个候选人可以当选的条件是他获得的票数比其他任何候选者都多。
输入描述:
第一行两个整数n和m,表示投票者的个数和候选人的个数。 接下来n行,每一行两个整数x和y,x表示这个投票者的投票对象,y表示需要花多少个糖果让这个人改变意向。 满足1 <= n, m <= 3000,1 <= x <= m,1 <= y <= 109。
输出描述:
一个整数,糖果的最小花费。
输入例子1:
1 2 1 20
输出例子1:
0
输入例子2:
5 5 2 5 3 5 4 5 5 6 5 1
输出例子2:
6
思路:假设1号需要k票能胜出,其他的人分为两类,一类的票数大于k-1,对于这一类需要转化他们当前的票数到k-1,转化的票数给1号,另一类是票数小于k-1。当对第一类人转化后,1号的票大于等于k时,那么1号必定胜出,因为其他人都小于k(之前大于k-1的都转化了),如果转化后1号的票数小于k(这个时候就要对第二类人进行转化啦),对第二类人的转化代价进行整合排序,由代价从小到大进行转化,直到1号的票数大于等于k。
注意这里的k怎么确定,先统计初始时票数最高的人,票数为p,则k=p+1开始,依次减小,每一个k都可以计算出一个的转化代价,所有转化代价的最小值即为所求。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 3005;
int voteNum, cadidateNum;
vector<int> G[N], rest;
int vis[N];
int votePerson, cost;
int max_vote = 0;
int res = 0;
int cur_vote = 0;
int result = N;
int main()
{
cin>>voteNum>>cadidateNum;
for (int i=0;i<voteNum;i++)
{
cin>>votePerson>>cost;
G[votePerson].push_back(cost);
vis[votePerson] ++;
}
for (int i=1;i<=cadidateNum;i++)
{
sort(G[i].begin(), G[i].end());
if (vis[votePerson] > max_vote)
{
max_vote = vis[votePerson];
}
}
for (int i=min(max_vote+1,votePerson);i>0;i--) //k由max_vote+1开始,注意,k不能大于参与投票的人数
{
cur_vote = vis[1];
res = 0;
for (int j=2;j<=cadidateNum;j++)
{
if (vis[j] > i-1) //判断当前候选人的票数是不是大于i-1,大于则转化
{
for (int m=0;m<(vis[j] - (i-1));m++)
{
res += G[j][m];
cur_vote++;
}
}else{ //小于则存储到数组中,后面同一排序
for (int m=0;m<G[j].size();m++)
{
rest.push_back(G[j][m]);
}
}
}
if (cur_vote < i) //如果一号的票数小于k,对第二类人进行转化
{
if (rest.size() < (i-cur_vote)) //第二类人都不够转化的,那就返回吧
{
continue;
}
sort(rest.begin(),rest.end()); //对第二类人按照代价进行排序
for (int m=0;m<i-cur_vote;m++) //转化
{
res += rest[m];
//cur_vote++;
}
}
rest.clear(); //清空,容易忘记
result = min(result, res);
//cout<<result<<endl;
}
cout<<result<<endl;
return 0;
}
7. 橡皮泥斑马
小易很喜欢斑马,因为它们身上黑白相间的花纹。
一天小易得到了一串橡皮泥,这串橡皮泥只有黑色和白色,小易想把这串橡皮泥重新拼凑一下,让这个橡皮泥串中最长的连续的黑白相间的子串最长,但是小易有强迫症,所以他可以对橡皮泥串进行以下的操作0次或多次:
把橡皮泥串从某个地方切割开,将两个得到的两个串同时翻转,再拼接在一起。
这个橡皮泥串可能太长了,所以小易没有办法计算最终可以得到的最长的连续的黑白相间的子串的长度,希望你能帮他计算出这个长度。
输入描述:
一个字符串s,只包含字母'b'和字母'w',分别表示黑色和白色的橡皮泥块。 满足1 <= |s| <= 105,|s|代表字符串的长度。
输出描述:
一个整数,表示改变之后最长的连续的黑白相间的子串的长度。
输入例子1:
bwbwb
输出例子1:
5
输入例子2:
wwb
输出例子2:
3
思路1:网上看的一个思路实现了一下,一个字符串分成两半、翻转再拼接其实就是环的问题,直接两个原字符串拼接,从前往后遍历即可。
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;
int main()
{
string data;
int res = 0;
getline(cin,data);
data = data + data;
for (int i=0;i<data.size();i++) //从字符串的每一位作为起始位置,统计符合的字符子串长度
{
int j=1;
while(i<data.size()-1 && data[i] != data[i+1]){ //看看是不是符合条件
j++;
i++;
}
res = res>j?res:j;
}
res = res > data.size()/2 ? data.size()/2:res; //不能大于原字符串的长度
cout<<res<<endl;
return 0;
}
思路2:暴力求解,递归
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;
int findLen(string data)
{
int res = 0, cur = 1;
for (int i=0;i<data.length()-1;i++)
{
if (data[i] != data[i+1])
{
cur++;
res = max(res, cur);
}else{
cur = 1;
}
}
return res;
}
void findMaxLen(string & data, int &max_len){
int len = data.length();
string data_pre, data_last;
for (int i=0;i<len-1;i++)
{
if (data[i] == data[i+1]) //如果不符合条件,从此处断开
{
if (data[0] != data[data.length()-1]) //从此处断开,首位能不能连接
{
data_pre = data.substr(0,i+1); //分成两个子串
data_last = data.substr(i+1, data.length()-i-1);
reverse(data_pre.begin(), data_pre.end()); //翻转
reverse(data_last.begin(), data_last.end());
data = data_pre + data_last; //重新拼接
max_len = max(max_len,findLen(data)); //统计符合条件的子串长度
findMaxLen(data, max_len); //递归
reverse(data_pre.begin(), data_pre.end()); //恢复现场
reverse(data_last.begin(), data_last.end());
data = data_pre + data_last;
}
}
}
max_len = max(max_len,findLen(data)); //容易遗漏,当字符串不需要断开时
}
int main()
{
string data;
int pre_len = 0, last_len = 0, len = 0;
int max_len = 0;
int high, commandNum;
vector<int> initCap, cap, res, commandTmp;
vector<vector<int>> command;
int tmp, M, N;
getline(cin,data);
findMaxLen(data, max_len);
cout<<max_len<<endl;
return 0;
}