序列交换
牛牛有一个长度为n的整数序列s,羊羊要在牛牛的序列中选择不同的两个位置,然后交换这两个位置上的元素。现在需要求出羊羊交换后可以得到的不同的序列个数。(注意被交换的两元素值可能相同)。
如序列{1, 47},输出1.羊羊必须交换仅有的两个元素,得到序列{47, 1}。羊羊必须交换,不能保留原有的序列。
{1, 2, 1},输出3.羊羊通过交换可以得到{2, 1, 1},{1, 1, 2},{1, 2, 1}这三个序列。
输入描述:
输入包括两行,第一行为一个整数n(2 ≤ n ≤ 50),即序列的长度。
第二行n个整数,表示序列的每个元素a_i(1 ≤ a_i ≤ 50),以空格分割。
输出描述:
输出一个整数,表示羊羊可以得到的不同的序列个数
输入例子:
3
1 2 1
输出例子:
3
思考:次题不要想复杂,我刚刚开始想着原有的序列生产A序列然后再A的基础上生成B,C然后就和题意就矛盾。
其实题意是只在原有序列基础上,交换两个不同的位置,生成多少个不同的序列,只有想办法去除重复序列,最后统计个数。
方法一:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
string int2string(int x) {
ostringstream stream;
stream << x;
return stream.str();
}
//添加"#"区别 [4 44] 和 [44 4]
//数组转化为字符串用于在set中去掉重复序列
string convert2string(vector<int> &v) {
string str = "";
for(unsigned i = 0; i < v.size(); i++) {
str += ("#" + int2string(v[i]));
}
return str;
}
int main()
{
vector<int> V;
set<string> mySet;
int n;
scanf("%d", &n);
int read;
for(int i = 0; i < n; i++) {
scanf("%d", &read);
V.push_back(read);
}
string newStr;
for(unsigned i = 0; i < V.size()-1; i++) {
for(unsigned j = i+1; j < V.size(); j++) {
swap(V[i], V[j]);
newStr = convert2string(V);
mySet.insert(newStr);
swap(V[i], V[j]);
}
}
cout << mySet.size() << endl;
return 0;
}
/**
测试用例:
3
4 44 4
19
6 13 26 9 39 7 31 7 28 22 43 6 5 26 44 44 40 4 5
**/
方法二:
思考:之前不经用用容器套容器,我突然觉得是时候要看看set的源码了。
#include
using namespace std;
int n;
set<vector <int> > mySet;//去重复。
vector<int> V;
int main() {
cin >> n;
int read;
for(int i = 0; i < n; i++) {
cin >> read;
V.push_back(read);
}
for(int i = 0; i < n-1; i++) {
for(int j = i+1; j < n; j++) {
swap(V[i], V[j]);
mySet.insert(V);
swap(V[i], V[j]);
}
}
cout << mySet.size() << endl;
return 0;
}
丑陋的字符串
牛牛喜欢字符串,但是他讨厌丑陋的字符串。对于牛牛来说,一个字符串的丑陋值是字符串中相同连续字符对的个数。比如字符串“ABABAABBB”的丑陋值是3,因为有一对”AA”和两对重叠的”BB”。现在给出一个字符串,字符串中包含字符’A’、’B’和’?’。牛牛现在可以把字符串中的问号改为’A’或者’B’。牛牛现在想让字符串的丑陋值最小,希望你能帮帮他。
输入描述:
输入包括一个字符串s,字符串长度length(1 ≤ length ≤ 50),字符串只包含’A’,’B’,’?’三种字符。
输出描述:
输出一个整数,表示最小的丑陋值
输入例子:
A?A
输出例子:
0
思考:前缀都是’?’部分都是有方案可以抵消掉的。然后把后半部分的情况处理一下。
效率及可读性需要学习方法二。
方法一:
#include
#include
#include
#include
using namespace std;
const int INF = 0x7fffffff;
void work();
string str;
//记录有多少个丑陋值
int cnt = 0;
int main()
{
getline(cin, str);
work();
cout << cnt << endl;
return 0;
}
int getCnt(string mystr) {
if(mystr.length() == 1) return 0;
int num = 0;
for(unsigned i = 1; i < mystr.length(); i++) {
if(mystr[i] == mystr[i-1]) {
num++;
}
}
return num;
}
void work()
{
//情况1:全是?的情况
if(str.find("A") == string::npos && str.find("B")==string::npos) {
cnt = 0;
return;
//情况2:没有?的情况
} else if(str.find("?") == string::npos) {
cnt = getCnt(str);
return;
}
//情况3 三种符合都有。
int posA = str.find("A");
int posB = str.find("B");
if(posA < 0) posA = INF;
if(posB < 0) posB = INF;
int firstIndex = min(posA, posB);
for(unsigned i = firstIndex; i < str.length(); i++) {
if(i == str.length()-1) break;
if(str[i+1] == str[i]) {
cnt++;
continue;
} else if(str[i+1] != '?' && str[i+1] != str[i]) {
continue;
} else {
if(str[i] == 'A') str[i+1] = 'B';
else str[i+1] = 'A';
}
}
}
方法二:(来自牛客网)
#include
using namespace std;
string str;
int calc(string s, int j) {
int res = 0;
for(int i = j + 1; i < s.size(); i++) {
if(s[i] == s[i - 1]) res++;
}
return res;
}
int main() {
cin >> str;
int pos = 0;
while(pos < str.size() && str[pos] == '?') pos++;
for(int i = pos + 1; i < str.size(); i++) {
if(str[i] == '?') {
if(str[i - 1] == 'A') str[i] = 'B';
else str[i] = 'A';
}
}
cout << calc(str, pos) << endl;
return 0;
}
黑白卡片
牛牛有n张卡片排成一个序列.每张卡片一面是黑色的,另一面是白色的。初始状态的时候有些卡片是黑色朝上,有些卡片是白色朝上。牛牛现在想要把一些卡片翻过来,得到一种交替排列的形式,即每对相邻卡片的颜色都是不一样的。牛牛想知道最少需要翻转多少张卡片可以变成交替排列的形式。
输入描述:
输入包括一个字符串S,字符串长度length(3 ≤ length ≤ 50),其中只包含’W’和’B’两种字符串,分别表示白色和黑色。整个字符串表示卡片序列的初始状态。
输出描述:
输出一个整数,表示牛牛最多需要翻转的次数。
输入例子:
BBBW
输出例子:
1
思路:因为最终结果只有两种,然后进行比对就可以了。
#include
#include
#include
using namespace std;
int work(string str);
int main()
{
string str;
getline(cin, str);
int res = work(str);
cout << res << endl;
return 0;
}
int work(string str) {
int cnt1 = 0;///BWBWBW
int cnt2 = 0;///WBWBWB
for(unsigned i = 0; i < str.length(); i++) {
if(i % 2 == 0) {
if(str[i] == 'W') cnt1++;
else cnt2++;
} else {
if(str[i] == 'B') cnt1++;
else cnt2++;
}
}
return min(cnt1, cnt2);
}
庆祝61
牛家庄幼儿园为庆祝61儿童节举办庆祝活动,庆祝活动中有一个节目是小朋友们围成一个圆圈跳舞。牛老师挑选出n个小朋友参与跳舞节目,已知每个小朋友的身高h_i。为了让舞蹈看起来和谐,牛老师需要让跳舞的圆圈队形中相邻小朋友的身高差的最大值最小,牛老师犯了难,希望你能帮帮他。
如样例所示:
当圆圈队伍按照100,98,103,105顺时针排列的时候最大身高差为5,其他排列不会得到更优的解
输入描述:
输入包括两行,第一行为一个正整数n(3 ≤ n ≤ 20)
第二行为n个整数h_i(80 ≤ h_i ≤ 140),表示每个小朋友的身高。
输出描述:
输出一个整数,表示满足条件下的相邻小朋友身高差的最大值。
输入例子:
4
100 103 98 105
输出例子:
5
思路:这是一道比较有趣味的题目,看代码应该就可以看懂大致思路。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int workFirst();
int workSecond();
const int maxn = 30;
int data[maxn];
vector<int> V;
int main()
{
int n;
scanf("%d", &n);
int read;
for(int i = 0; i < n; i++) {
scanf("%d", &read);
V.push_back(read);
}
sort(V.begin(), V.end());
int res = workFirst();
res = max(res, workSecond());
printf("%d\n", res);
return 0;
}
int workFirst() {
data[15] = V[0];
int left = 14;
int right = 16;
for(unsigned i = 1; i < V.size(); i++) {
if(i%2) {
data[left--] = V[i];
} else {
data[right++] = V[i];
}
}
left++;
right--;
int maxValue = fabs(data[right]-data[left]);
for(int i = left; i < right; i++) {
maxValue = max(maxValue, data[i+1]-data[i]);
}
return maxValue;
}
int workSecond() {
data[15] = V[0];
int left = 14;
int right = 16;
for(unsigned i = 1; i < V.size(); i++) {
if(i%2==0) {
data[left--] = V[i];
} else {
data[right++] = V[i];
}
}
left++;
right--;
int maxValue = fabs(data[right]-data[left]);
for(int i = left; i < right; i++) {
maxValue = max(maxValue, data[i+1]-data[i]);
}
return maxValue;
}
/**
测试:
11
109 111 135 123 127 112 89 125 106 82 83
*/
黑化的牛牛
牛牛变得黑化了,想要摧毁掉地球。但他忘记了开启地球毁灭器的密码。牛牛手里有一个字符串S,牛牛还记得从S中去掉一个字符就恰好是正确的密码,请你帮牛牛求出他最多需要尝试多少次密码。
如样例所示S = “ABA”,3个可能的密码是”BA”, “AA”, “AB”.
当S = “A”, 牛牛唯一可以尝试的密码是一个空的密码,所以输出1.
输入描述:
输入包括一个字符串S,字符串长度length(1 ≤ length ≤ 50),其中都是从’A’到’Z’的大写字母。
输出描述:
输出一个整数,表示牛牛最多需要尝试的密码次数。
输入例子:
ABA
输出例子:
3
思路:其实问题是求去掉一个字母一共有多少种情况, 用set去重。
#include
#include
#include
#include
using namespace std;
int work(string str);
int main()
{
string str;
getline(cin, str);
cout << work(str) << endl;
}
int work(string str) {
set<string> passWordSet;
string newStr;
for(unsigned i = 0; i < str.size(); i++) {
if(i == 0) {
newStr = str.substr(1, str.length()-1);
passWordSet.insert(newStr);
} else {
newStr = str.substr(0, i) + str.substr(i+1, str.length()-i-1);
passWordSet.insert(newStr);
}
}
return passWordSet.size();
}
膨胀的牛牛
牛牛以草料为食。牛牛有一天依次遇到n堆被施展了魔法的草料,牛牛只要遇到一堆跟他当前相同大小的草料,它就会把草料吃完,而使自己的大小膨胀一倍。一开始牛牛的大小的是A,然后给出牛牛依次遇到的n堆草料的大小。请计算牛牛最后的大小。
输入描述:
输入包括两行,第一行包含两个整数n和A(1 ≤ n ≤ 200, 1 ≤ A ≤ 1,000,000,000)
第二行包括n个整数,表示牛牛依次遇到的草料堆大小a_i(1 ≤ a_i ≤ 1,000,000,000)
输出描述:
输出一个整数,表示牛牛最后的大小。
输入例子:
5 1
2 1 3 1 2
输出例子:
4
#include
#include
#include
#include
using namespace std;
int main()
{
int n, currentSize;
vector<int> V;
scanf("%d%d", &n, ¤tSize);
int read;
for(int i = 0; i < n; i++) {
scanf("%d", &read);
V.push_back(read);
}
for(unsigned i = 0; i < V.size(); i++) {
if(currentSize == V[i]) {
currentSize *= 2;
}
}
printf("%d\n", currentSize);
return 0;
}
牛客网题解:https://www.nowcoder.com/discuss/28544