大体题意:
输入许多文章,在输入许多命令,按照指定的格式输出文章或者对应的行。文章最多100个,最多总共1500行,命令最多50000个!
16751099 | 1597 | Searching the Web | Accepted | C++ | 1.048 | 2016-01-25 03:10:22 |
看上去数据量有点小,怎么做都行,但第一遍就TLE了,如果输入一个命令,在全文搜索一遍,这样做不行的,会超时,所以不能直接扫描string
所以又得不用string的find,而且能查找,自然就先想到了map映射!
无意中看到了原文中给的图片!其实查找方法在图片已经体现出来了!
每一个单词都可以映射到指定的文章序号和行序号!但由于可以有重复的单词,所以可以建立一个vector一个一个存取。
所以可以建立一个map<string,vector<pair<int,int> > >,键是指定的单词,值是pair数组,而pair first是文章序号,pair second是行序号!
这一个map就可以解决除了NOT的问题!可以解决3个指令!
而NOT可以根据文章序号查找单词!
所以在建立一个map<string,vector<int> >dest[maxn],dest数组的索引就是文章的序号,string就是第i文章的单词,映射到行数!这样就可以解决NOT指令了
NOT是输出整个文章,其余是对应的行,所以把每一行存到vector<string>String,存进去的是原内容,而映射的都是小写单词!
输出整个文章需要得到,一个文章的开始行数和结尾行数,为了避免循环找行数,所以可以直接建立一个pair<int,int>lines[maxn], lines数组索引为文章的序号,first为起始位置,second为结束位置!在输入的时候就记录!
技巧:
1.可以把只有一个单词的命令当作OR来处理,第一个单词是原单词,第二个单词是文章不可能存在的单词 比如:^_^!!
2.把AND和OR指令写成一个函数,把NOT写成一个函数!
3.在输出时因为是按行数从小到大输出的, 而且不重复输出同一行,但上面的判断会得到同一行,所以可以把上面得到的判断的行数存到set里这样即从小到大排了序,而且没有重复!在根据set输出即可!
让我不爽的是,第二遍是WA,原因就是分隔符“-”是10个,自己打成了9个,但样例输出就是9个啊,但在原文阐述中,确实是10个,!!
代码如下:
#include<string> #include<iostream> #include<set> #include<vector> #include<map> #include<sstream> #include<cctype> using namespace std; int n,T; const int maxn = 1500 + 10; const string sep[3] = {"**********","----------","=========="}; pair<int,int>lines[maxn]; vector<string>String; map<string,vector<pair<int,int> > >word; map<string,vector<int> >dest[maxn]; void deal(const string &s,const string &t,const string & flag){ int kase = 0; for (int i =0 ;i < n; ++i){ set<int>out;out.clear(); bool flag_s=false,flag_t=false; if (dest[i].count(s)){for(int k=0;k<dest[i][s].size();++k)out.insert(dest[i][s][k]);flag_s=true;} if (dest[i].count(t)){for(int k=0;k<dest[i][t].size();++k)out.insert(dest[i][t][k]);flag_t=true;} if (flag == "OR"){ if (flag_s || flag_t){ if (kase++)cout << sep[1] << endl; for (set<int> :: iterator it = out.begin();it != out.end(); ++it)cout << String[*it] << endl; } }else{ if (flag_s && flag_t){ if (kase++)cout << sep[1] <<endl; for (set<int>::iterator it = out.begin();it != out.end(); ++it)cout << String[*it] << endl; } } } if (!kase)cout << "Sorry, I found nothing." << endl; cout << sep[2] <<endl; } void deal2(const string &s){ int kase = 0; set<int>out;out.clear(); for (int i = 0; i < n; ++i){if (!dest[i].count(s)){out.insert(i);kase++;}} for (set<int>::iterator it = out.begin(); it != out.end(); ++it){ if(it != out.begin())cout << sep[1] <<endl; for (int i = lines[*it].first; i < lines[*it].second; ++i)cout << String[i] << endl; } if (!kase)cout << "Sorry, I found nothing." << endl; cout << sep[2] << endl; } int main() { string s,t,h; cin >> n; getline(cin,s); for (int i = 0; i < n; ++i){ int cnt = 0; while(getline(cin,s) && s != sep[0]){ if (!cnt){lines[i].first=String.size();if (i)lines[i-1].second=String.size();} ++cnt; String.push_back(s); for (int j=0; j<(int)s.size();++j){if (!isalpha(s[j]))s[j]=' ';else s[j] = tolower(s[j]);} stringstream ss(s); while(ss >> t){ pair<int,int>temp;temp.first=i;temp.second=String.size()-1; if (!word.count(t))word[t]=vector<pair<int,int> >(); word[t].push_back(temp); if (!dest[i].count(t))dest[i][t]=vector<int>(); dest[i][t].push_back(String.size()-1); } } }lines[n-1].second=String.size(); cin >> T; getline(cin,s); while(T--){ getline(cin,h); int AND = h.find("AND"),OR = h.find("OR"),NOT = h.find("NOT"); if (AND != -1){s=h.substr(0,AND-1);t=h.substr(AND+4);deal(s,t,"AND");} else if (OR != -1){s=h.substr(0,OR-1);t=h.substr(OR+3);deal(s,t,"OR");} else if (NOT != -1){s=h.substr(NOT+4);deal2(s);} else {s=h;t="^_^!",deal(s,t,"OR");} } return 0; }