回收站选址
这道题是第一次提交满分,之前是因为数值涉及太大,我不知道怎么存储以及判断会省时一些,就一直没做;这次做用到了STL,也算是做了这么多第三题回看第二题的一些简便吧
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
set<PII> se;
int res[10];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n; cin >> n;
for(int i = 0;i < n;i ++){
int x, y; cin >> x >> y;
se.insert({x, y});
}
int idx[] = {-1, 1, 0, 0, -1, -1, 1, 1};
int idy[] = {0, 0, -1, 1, -1, 1, -1, 1};
for(auto point : se){
int x = point.first, y = point.second;
bool flag = true;
for(int i = 0;i < 4 && flag;i ++){ //看是否符合要求
int dx = x + idx[i];
int dy = y + idy[i];
if(!se.count({dx, dy})) { flag = false; break; }
}
if(flag){ //符合要求的基础上,统计得分
int cnt = 0;
for(int i = 4;i < 8;i ++){
int dx = x + idx[i];
int dy = y + idy[i];
if(se.count({dx, dy})) cnt ++;
}
res[cnt] ++;
}
}
for(int i = 0;i <= 4;i ++){
cout << res[i] << endl;
}
return 0;
}
化学方程式
第一把官网提交是80分,acwing通过的答案是 9 / 11;先贴出80分的初始代码:
#include<bits/stdc++.h>
#define key first
#define value second
using namespace std;
typedef pair<string, int> PSI;
int to_int(string str)
{
stringstream ssin(str);
int x;
ssin >> x;
return x;
}
bool upper(char ch)
{
if(ch >= 'A' && ch <= 'Z') return true;
return false;
}
bool lower(char ch)
{
if(ch >= 'a' && ch <= 'z') return true;
return false;
}
bool number(char ch)
{
if(ch >= '0' && ch <= '9') return true;
return false;
}
unordered_map<string, int> cal(string str)
{
unordered_map<string, int> res;
vector<string> expr;
for(int i = 0, j = 0; i < str.size(); i = j + 1){ //将str用'+'分割开来
j = str.find('+', i); //从下标i开始找+号
if(j == -1) j = str.size();
expr.push_back(str.substr(i, j - i));
}
for(auto item : expr){ //对于每一个物质
unordered_map<string, int> cnt; //建立一个小的map为了处理好下标乘系数
int coef = 1, pos = 0;
if(number(item[0])){ //提取系数
while(number(item[pos])) pos ++;
coef = to_int(item.substr(0, pos));
}
while(pos < item.size()){
if(upper(item[pos])){ //元素
string ele = "";
if(pos < item.size() - 1 && lower(item[pos + 1])) { //大写+小写的组合
ele = item[pos] + item[pos + 1];
pos += 2;
}
else { ele = item[pos]; pos ++; }
if(pos < item.size() && number(item[pos])){ //如果元素后面跟了数字,则开始找下标
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
int x = to_int(item.substr(l, pos));
//cout << "ele"<<ele<<"的下标是"<<x<<endl;
cnt[ele] += x;
}
else cnt[ele] ++; //出现一次
}
else if(item[pos] == '('){ //开始处理括号
stack<PSI> s;
s.push({"(", 0}); pos ++;
unordered_map<string, int> temp; //是为了处理下标
while(!s.empty() && pos < item.size()){
//跟遇到元素的处理方式其实相同
if(upper(item[pos])){ //元素
string ele;
if(pos < item.size() - 1 && lower(item[pos + 1])) { //大写+小写的组合
ele = item[pos] + item[pos + 1];
pos += 2;
}
else { ele = item[pos]; pos ++; }
int sub = 1;
if(pos < item.size() && number(item[pos])){ //元素后面跟了数字
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
sub = to_int(item.substr(l, pos));
}
s.push({ele, sub}); //压入元素
}
else if(item[pos] == '(') { s.push({"(", 0}); pos ++; } //只是入栈不做操作 | 此时不可能是item的末尾,不涉及越界
else if(item[pos] == ')'){
pos ++; int sub = 1; //先提取括号外的下标
if(pos < item.size() && number(item[pos])){
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
sub = to_int(item.substr(l, pos)); //下标更新
}
//开始弹出,和当前反括号匹配的括号内的元素,都要乘下标
auto x = s.top(); s.pop();
while(x.key != "("){
temp[x.key] += (x.value * sub);
x = s.top(); s.pop();
}
}
}
//将temp里的并到cnt里去
for(auto x : temp){
cnt[x.key] += x.value;
}
}
}
//所有个数都要乘以系数
for(auto x : cnt){
res[x.key] = res[x.key] + x.value * coef;
}
}
return res;
}
bool judge(string expr)
{
unordered_map<string, int> eleft, eright; //等式左右两侧各一个map
int i = 0;
while(expr[i] != '=') i ++;
string ex1 = expr.substr(0, i);
string ex2 = expr.substr(i + 1);
eleft = cal(ex1);
eright = cal(ex2);
if(eleft.size() != eright.size()) return false;
for(auto x : eleft){
if(eright[x.key] != x.value) return false;
}
return true;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n; cin >> n;
string line;
while(n --){
cin >> line;
bool flag = judge(line);
if(flag) cout << "Y\n";
else cout << "N\n";
}
return 0;
}
做这么几次字符串的题目发现,字符串题目的思维难度其实不大,最大的难点就是很难将所有情况考虑全面,属于是有例子在,完全可以满分;但是会很容易忽略一些细节,导致搜索的过程中提前将答案也过滤掉了
所以这次修改也是基于ACWING的答案上;在比对时我发现了嵌套时出现了这样的问题:
我简化了左侧的表达式,使得问题更加清楚;K明显不止32个,我之前的做法遗漏了外层括号
在之前的做法中,每遇到一个回括号,我就开始弹出栈内的元素直到遇见(,也就是与之匹配的首部括号,然后根据下标更新括号内的元素数目。
这就是问题所在。栈顶元素按照逻辑是最内层的括号里的元素!它在所有括号的内部。而在上述做法中,这些元素被更新一次就被弹出了,而实际上这些元素应该被更新到最外层的括号截止,才算完成。所以在修改后的做法中,我设置了一个容器先暂存这些弹出的栈顶元素,如果栈非空的话,需要将这些元素弹回(在外层括号的下标还要做乘法)
最终修改得到满分答案,官网截图以及代码如下:
#include<bits/stdc++.h>
#define key first
#define value second
using namespace std;
typedef pair<string, int> PSI;
//将字串转化为整数
int to_int(string str)
{
stringstream ssin(str);
int x;
ssin >> x;
return x;
}
//判断是否为大写字母
bool upper(char ch)
{
if(ch >= 'A' && ch <= 'Z') return true;
return false;
}
//判断是否为小写字母
bool lower(char ch)
{
if(ch >= 'a' && ch <= 'z') return true;
return false;
}
//判断是否为数字
bool number(char ch)
{
if(ch >= '0' && ch <= '9') return true;
return false;
}
//计算一个fomular的所有元素及其个数
unordered_map<string, int> cal(string str)
{
unordered_map<string, int> res;
vector<string> expr;
for(int i = 0, j = 0; i < str.size(); i = j + 1){ //将str用'+'分割开来
j = str.find('+', i); //从下标i开始找+号
if(j == -1) j = str.size();
expr.push_back(str.substr(i, j - i));
}
for(auto item : expr){ //对于每一个物质
unordered_map<string, int> cnt; //建立一个小的map为了处理好下标乘系数
int coef = 1, pos = 0;
if(number(item[0])){ //提取系数
while(number(item[pos])) pos ++;
coef = to_int(item.substr(0, pos));
}
while(pos < item.size()){ //分析物质
if(upper(item[pos])){ //元素
string ele = "";
if(pos < item.size() - 1 && lower(item[pos + 1])) { //大写+小写的组合
ele = item[pos] + item[pos + 1];
pos += 2;
}
else { ele = item[pos]; pos ++; }
if(pos < item.size() && number(item[pos])){ //如果元素后面跟了数字,则开始找下标
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
int x = to_int(item.substr(l, pos));
cnt[ele] += x;
}
else cnt[ele] ++; //出现一次
}
else if(item[pos] == '('){ //开始处理括号
stack<PSI> s; //s中压入括号,或者括号内的元素及其出现次数
s.push({"(", 0}); pos ++;
vector<PSI> temp; //栈顶弹出元素暂存区
while(!s.empty() && pos < item.size()){
//跟遇到元素的处理方式其实相同
if(upper(item[pos])){ //出现元素
string ele;
if(pos < item.size() - 1 && lower(item[pos + 1])) { //大写+小写的组合
ele = item[pos] + item[pos + 1];
pos += 2;
}
else { ele = item[pos]; pos ++; }
int sub = 1;
if(pos < item.size() && number(item[pos])){ //元素后面跟了数字
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
sub = to_int(item.substr(l, pos));
}
s.push({ele, sub}); //压入元素及其个数
}
else if(item[pos] == '(') { s.push({"(", 0}); pos ++; } //只是入栈不做操作 | 此时不可能是item的末尾,不涉及越界
else if(item[pos] == ')'){
pos ++; int sub = 1; //先提取括号外的下标
if(pos < item.size() && number(item[pos])){
int l = pos;
while(pos < item.size() && number(item[pos])) pos ++;
sub = to_int(item.substr(l, pos)); //下标更新
}
//开始弹出,和当前反括号匹配的括号内的元素,都要乘下标
auto x = s.top(); s.pop();
while(x.key != "("){
x.value *= sub;
temp.push_back(x); //暂存到temp中去
x = s.top(); s.pop();
}
if(!s.empty()){ //还没到最大的括号(注意内层括号被包括在外层括号之中)
//暂存区中的元素需要弹回栈内
for(auto x : temp){
s.push(x);
}
temp.clear();
}
}
}
//将temp里的并到cnt里去
for(auto x : temp){
cnt[x.key] += x.value;
}
}
}
//所有元素个数都要乘以物质个数(系数)
for(auto x : cnt){
res[x.key] = res[x.key] + x.value * coef;
}
}
return res;
}
bool judge(string expr)
{
unordered_map<string, int> eleft, eright; //等式左右两侧各一个map
int i = 0;
while(expr[i] != '=') i ++;
string ex1 = expr.substr(0, i);
string ex2 = expr.substr(i + 1);
eleft = cal(ex1);
eright = cal(ex2);
if(eleft.size() != eright.size()) return false;
for(auto x : eleft){
if(eright[x.key] != x.value) return false;
}
return true;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n; cin >> n;
string line;
while(n --){
cin >> line;
bool flag = judge(line);
if(flag) cout << "Y\n";
else cout << "N\n";
}
return 0;
}
OVER,以前的第三题真是简单啊!!!尖叫!以及,可以修改得到满分真的特别有成就感!!