目录
- 第1题
- 第2题
- 第3题
第1题
输入描述:
本题为多组测试数据,第一行输入一个正整数,代表测试数据组数。
对于每组测试数据,一行输入一个长度不超过1000的01串,代表初始形态。
输出描述:
对于每组测试数据,如果牛妹得分高,则在第一行输出NiuMei,第二行输出一个分数代表牛妹比牛牛高几分;
如果牛牛得分高,则在第一行输出NiuNiu,第二行输出一个分数代表牛牛比牛妹高几分;
如果两个人分数相同,则只需要在一行输出Draw.
输入例子1:
2
111111
111011
输出例子1:
Niumei
6
Niumei
1
例子说明1:
第一个测试数据中,牛妹可以一次性消除所有字符,得到6分,而牛牛0 分。
第二个测试数据中,牛妹先消除前三个字符,得到3 分,剩余字符为011,牛牛选择末尾两个字符消除,得到2分,至此,字符只剩下0,牛妹消除掉这个字符,但由于该字符是0,所以不得分。总计牛妹得到3分,牛牛得到2分。
我的代码
#include <iostream>
#include <string>
#include <string.h>
#include <stdio.h>
using namespace std;
int myremove(string& str)
{
//记得排除极端情况,全0或全1
//找字符串的最长1相同子字符串,记录其起始位置和结束位置
//先消除1
int a[(const int)str.size()];
memset(a, 0x0000, sizeof(a));//数组a[i]表示以str[i]结尾的子字符串中连续1的个数
for(int i = 0; i < str.size(); i++)
{
if(str[i] == '1')
a[i] = 1;
}
for(int i = 1; i < str.size(); i++)
{
if(str[i] == '1' && str[i-1] == str[i])
a[i] = a[i-1] + 1;
}
//找a[]中的最大值
int index = 0, val = a[0];
for(int i = 0; i < str.size(); i++)
{
if(a[i] > val)
{
val = a[i];
index = i;
}
}
if(val == 0)
return -1;
string new_str;
//下标i=index-val...index这段不要
new_str = str.substr(0, index-val+1) + str.substr(index+1);
str.clear();
str = new_str;
return val;
}
int main()
{
int T;
cin >> T;
while(T--)
{
string str;
cin >> str;
int mei = 0, niu = 0;
while(str.size() != 0)
{
int add1 = myremove(str);
if(add1 == -1) break;
mei += add1;
int add2 = myremove(str);
if(add2 == -1) break;//没有1时返回-1
niu += add2;
}
if(mei > niu)
{
cout << "Niumei" << endl;
cout << mei - niu << endl;
}
else if(mei < niu)
{
cout << "NiuNiu" << endl << niu - mei << endl;
}
else
cout << "Draw" << endl;
}
return 0;
}
第2题
我的代码
#include <iostream>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <queue>
using namespace std;
const int N = 100010;
int attack[N];
int money[N];
int res[N];//存放每个猎人能够获得的最大金钱
unordered_map<int, int> h;
int n, k;
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i++)
{
int tmp;
cin >> tmp;
attack[i] = tmp;
h[tmp] = i;
}
for(int i = 0; i < n; i++)
{
int tmp;
cin >> tmp;
money[i] = tmp;
res[i] = tmp;
}
//如果k等于0,直接输出res
if(k == 0)
{
for(int i = 0; i < n; i++)
cout << res[i] << ' ';
cout << endl;
return 0;
}
sort(attack, attack+n);//对攻击力从小到大排序,按照h[attack[i]]可知道attack[i]在原数组中的下标
priority_queue<int, vector<int>, greater<int>> q;
//小根堆q,堆顶存放最小值。用来维护k个最大金额。
int sum = 0;//存储k个最大金额之和
for(int i = 1; i < n; i++)
{
int val = money[h[attack[i-1]]];
if(q.size() < k)
{
sum += val;
q.push(val);
}
else
{
if(q.top() < val)
{
sum -= q.top();
sum += val;
q.pop();
q.push(val);
}
}
res[h[attack[i]]] += sum;
}
for(int i = 0; i < n; i++)
cout << res[i] << ' ';
cout << endl;
return 0;
}
第3题
考察字典树trie,它用来高效地存储和查找字符串。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e7 + 10;//10^5个字符串,每个字符串18位,每位最多有10个字结点,故10^7
int son[N][10];//字典树,第1个参数表示结点序号,第2个参数表示该结点的可能存在的子结点编号,值表示存在的子结点序号
//对于结点x,son[x][0]表示结点x的第0个子结点,son[x][1]表示结点x的第1个子结点...
//如果son[x][1] == 0,表示结点x的第1个子结点为空!
//注意根结点也用0表示!
int cnt[N];
//原字典树中cnx[x]表示以结点x结尾的单词有多少个
//在这里做了变形,cnt[x]表示经过结点x的单词个数
int idx;//表示当前用到了哪个结点
int n, m;
void insert(string str)
{
int p = 0;
for(int i = 0; i < str.size(); i++)
{
int u = str[i] - '0';
if(!son[p][u]) son[p][u] = ++idx;
cnt[son[p][u]]++;
p = son[p][u];
}
}
void query(string str, int& k, int& num)//k表示最大相似度,num表示次数
{
int p = 0;
num = n;
for(int i = 0; i < str.size(); i++)
{
int u = str[i] - '0';
if(!son[p][u])//如果子节点son[p][u]不存在
{
k = i;//不存在完全相同的身份证,所以k=18不用考虑
return;
}
num = cnt[son[p][u]];
p = son[p][u];
}
return;
}
int main()
{
cin >> n >> m;
string str;
int t = n;
while(t--)
{
cin >> str;
insert(str);
}
t = m;
while(t--)
{
cin >> str;
int k, num;
query(str, k, num);
cout << k << " " << num << endl;
}
return 0;
}
待更新