1. 卖菜
15ms | 100分
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int first[N], second[N];
int main()
{
int n; cin >> n;
for(int i = 0;i < n;i ++) scanf("%d", &first[i]);
for(int i = 0;i < n;i ++){
if(i == 0){
printf("%d ", (first[i] + first[i + 1]) / 2);
}else if(i == n - 1){
printf("%d ", (first[i] + first[i - 1]) / 2);
}else{
printf("%d ", (first[i] + first[i + 1] + first[i - 1]) / 3);
}
}
return 0;
}
2. 买菜
15ms | 100分
其实看到这题的第一想法就是:每录入一个区间就让区间上的数全部加一,最后找到区间大于1的部分就是重叠的区间。但是当时觉得时间复杂度太高加上太久没做前缀差分的题目就去做别的方法结果磨了个把小时拿了个20分…
话说前缀差分在第二题的流行是不是就是从这个时候开始的
//用差分和前缀和的做法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int re[N];
int main()
{
memset(re, 0, sizeof re); //初始化差分数组
int n; scanf("%d", &n);
int left, right;
for(int i = 0;i < 2 * n;i ++){
scanf("%d%d", &left, &right);
re[left] ++;
re[right] --; //注意两个区间的端点重合不计入,所以可以舍弃头或者尾部,算是容易出错的点
}
long long sum = 0, res = 0;
for(int i = 1;i < N;i ++){
res += re[i];
if(res > 1) sum ++;
}
cout << sum;
return 0;
}
先给一个80分答案,基本上算是独立写的一个版本
但是可恶的是我通过acwing发现并不是优化问题而是逻辑问题
错误的逻辑在于我对着示例写的时候,将后代元素选择的搜索范围仅划分到了当前候选元素的子元素,也就是我只允许一层层的搜索下去。而题目中要求的是可以“跳层搜索”,比如html div p和div p的搜索结果应该一样,但是若div的外层有body包裹的情况下则搜索不到
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
unordered_map<string, vector<int> > element; //记录每一种标签分别在哪几行有
string line_element[N]; //元素对应表,用行号即可读取到元素名称
string line_id[N]; //id对应表,用行号即可读取到id名称
unordered_map<int, vector<int> > level; //记录每一个深度有哪些元素
unordered_map<int, vector<int> > child; //记录每行的子元素行
//处理标签的大小写不敏感
string lower(string label)
{
string str = ""; //a - A = 32
for(int i = 0;i < label.size();i ++){
if(label[i] >= 'a' && label[i] <= 'z') {
//是小写字母
str += label[i];
}
else{
str += (label[i] + 32);
}
}
return str;
}
//比较两个字符串内容是否相同
bool compare(string str1, string str2)
{
if(str1.size() != str2.size()) return false;
int len = str1.size();
for(int i = 0;i < len;i ++){
if(str1[i] != str2[i])
return false;
}
return true;
}
void handle(string line, int index)
{
stringstream ssin(line);
vector<string> words; string w;
while(ssin >> w)
words.push_back(w);
int len = words.size(); //要么为2要么为1
int depth, cnt = 0, i = 0;
while(line[i] == '.'){
i ++; cnt ++;
}
depth = cnt / 2;
string ele = words[0].substr(i, words[0].size());
ele = lower(ele);
element[ele].push_back(index); //index行有元素ele
line_element[index] = ele;
level[depth].push_back(index); //当前深度有行号为index的元素
if(len == 2){
string id = words[1];
element[id].push_back(index); //为了方便id查询(id可以直接定位)
line_id[index] = id;
}
if(index == 1) return; //为根元素没有父元素
int fa_depth = depth - 1; //父元素的深度
int fa_size = level[fa_depth].size();
int father_index = level[fa_depth][fa_size - 1]; //取出最近的fa_depth深度的元素,它一定是该元素的父元素
child[father_index].push_back(index);
}
//利用选择器挑选元素
void selector(string query)
{
//标签查询, id查询, 后代查询
stringstream ssin(query);
vector<string> words; string word;
while(ssin >> word){
if(word[0] != '#') word = lower(word);
words.push_back(word);
}
int len = words.size();
string key = words[0];
if(len == 1){ //可能为元素查询或者是Id查询, 直接从element里面获取答案
if(element.count(key)){
vector<int> ans = element[key];
cout << ans.size() << ' ';
for(auto x : ans) cout << x << ' ';
}
else cout << 0; //没有相关查询
return;
}
//否则为后代查询
vector<int> init_candidate = element[key]; //以最大的父元素得到初始候选集
set<int> dyna_candidate; //动态候选集,随着搜索更新
int i = 1; //定位当前查找的元素名字
bool flag = true;
while(flag){
dyna_candidate.clear(); //清空新的候选集
for(auto line : init_candidate){ //对于现有候选集中的每一行
for(auto ch : child[line]){ //遍历它的每个子元素
//cout <<"当前的候选行:"<<line<<" 它的子元素是 "<< ch<<endl;
if(!compare(words[i], line_element[ch]))
if(!compare(words[i], line_id[ch]))
continue;
dyna_candidate.insert(ch);
}
}
if(dyna_candidate.size() == 0){ //新的候选集数量为空
cout << 0;
flag = false;
return;
}
if(i == len - 1){ //此时得到的候选集就为答案
cout << dyna_candidate.size() <<' ';
for(auto x : dyna_candidate){
cout << x << ' ';
}
flag = false;
return;
}
i ++;
init_candidate.clear();
for(auto x : dyna_candidate)
init_candidate.push_back(x);
}
/*
for(auto x : words)
cout << x <<endl;
cout <<endl;*/
}
int main()
{
int n, m;
cin >> n >> m;
string line; getline(cin, line);
for(int i = 1;i <= n;i ++){
getline(cin, line);
handle(line, i);
}
while(m --){
getline(cin, line);
selector(line);
cout << endl;
}
return 0;
}
对照着acwing答案的不同修改
完全不需要剪枝!对于当前候选集合的每一个子元素,不管有没有匹配到当前需要匹配的部分,都需要加入到初始候选集中,出循环的唯一条件就是搜索到当前元素没有更多的子元素。
为什么搜索到了也要加到init_candidate
中呢,主要是因为下面这个例子
..........e
............h2f
..............o
................o
................e
................C6L
..................h2f
如果不将匹配的也加入,则在找e h2f
时只会输出第二行,而最后一行会因为在已经搜索到了的第二行的子元素中而被忽略,导致答案缺少
唯一的不同是如果搜索到了,要将它的子元素加入动态候选集,也就是下一阶段的初始候选集的备选集合中,要通过这个动态候选集更新下一个阶段的初始候选集的。
这里幸亏我开始用了一个定位当前搜索的i
花了我40min修改得到满分答案!撒花!
只要在下面的108行加一句init_candidate.push_back(ch);
就好了,这就是算法的魅力 (折磨)吗
满分代码如下:
0ms | 100分
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
unordered_map<string, vector<int> > element; //记录每一种标签分别在哪几行有
string line_element[N]; //元素对应表,用行号即可读取到元素名称
string line_id[N]; //id对应表,用行号即可读取到id名称
unordered_map<int, vector<int> > level; //记录每一个深度有哪些元素
unordered_map<int, vector<int> > child; //记录每行的子元素行
//处理标签的大小写不敏感
string lower(string label)
{
string str = ""; //a - A = 32
for(int i = 0;i < label.size();i ++){
if(label[i] >= 'a' && label[i] <= 'z') {
//是小写字母
str += label[i];
}
else{
str += (label[i] + 32);
}
}
return str;
}
//比较两个字符串内容是否相同
bool compare(string str1, string str2)
{
if(str1.size() != str2.size()) return false;
int len = str1.size();
for(int i = 0;i < len;i ++){
if(str1[i] != str2[i])
return false;
}
return true;
}
void handle(string line, int index)
{
stringstream ssin(line);
vector<string> words; string w;
while(ssin >> w)
words.push_back(w);
int len = words.size(); //要么为2要么为1
int depth, cnt = 0, i = 0;
while(line[i] == '.'){
i ++; cnt ++;
}
depth = cnt / 2;
string ele = words[0].substr(i, words[0].size());
ele = lower(ele);
element[ele].push_back(index); //index行有元素ele
line_element[index] = ele;
level[depth].push_back(index); //当前深度有行号为index的元素
if(len == 2){
string id = words[1];
element[id].push_back(index); //为了方便id查询(id可以直接定位)
line_id[index] = id;
}
if(index == 1) return; //为根元素没有父元素
int fa_depth = depth - 1; //父元素的深度
int fa_size = level[fa_depth].size();
int father_index = level[fa_depth][fa_size - 1]; //取出最近的fa_depth深度的元素,它一定是该元素的父元素
child[father_index].push_back(index);
}
//利用选择器挑选元素
void selector(string query)
{
//标签查询, id查询, 后代查询
stringstream ssin(query);
vector<string> words; string word;
while(ssin >> word){
if(word[0] != '#') word = lower(word);
words.push_back(word);
}
int len = words.size();
string key = words[0];
if(len == 1){ //可能为元素查询或者是Id查询, 直接从element里面获取答案
if(element.count(key)){
vector<int> ans = element[key];
cout << ans.size() << ' ';
for(auto x : ans) cout << x << ' ';
}
else cout << 0; //没有相关查询
return;
}
//否则为后代查询
vector<int> init_candidate = element[key]; //以最大的父元素得到初始候选集
set<int> dyna_candidate; //动态候选集,随着搜索更新
int i = 1; //定位当前查找的元素名字
bool flag = true;
while(flag){
dyna_candidate.clear(); //清空新的候选集
for(int j = 0;j < init_candidate.size();j ++){ //对于现有候选集中的每一行
int line = init_candidate[j];
for(auto ch : child[line]){ //遍历它的每个子元素
init_candidate.push_back(ch);
if(!compare(words[i], line_element[ch]))
if(!compare(words[i], line_id[ch])){
continue;
}
dyna_candidate.insert(ch);
}
}
if(dyna_candidate.size() == 0){ //新的候选集数量为空
cout << 0;
flag = false;
return;
}
if(i == len - 1){ //此时得到的候选集就为答案
cout << dyna_candidate.size() <<' ';
for(auto x : dyna_candidate){
cout << x << ' ';
}
flag = false;
return;
}
i ++;
init_candidate.clear();
for(auto x : dyna_candidate)
init_candidate.push_back(x);
}
/*
for(auto x : words)
cout << x <<endl;
cout <<endl;*/
}
int main()
{
int n, m;
cin >> n >> m;
string line; getline(cin, line);
for(int i = 1;i <= n;i ++){
getline(cin, line);
handle(line, i);
}
while(m --){
getline(cin, line);
selector(line);
cout << endl;
}
return 0;
}