A - Filter
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
int x;
cin>>x;
if(x%2==0)cout<<x<<" ";
}
return 0;
}
B - ASCII Art
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=110;
int a[N][N];
int main()
{
int h,w;
cin>>h>>w;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
if(a[i][j]==0) cout<<'.';
else{
printf("%c",'A'+a[i][j]-1);
}
}
cout<<endl;
}
return 0;
}
C - Merge Sequences
大致题意就是对于A的每一个数,输出它们在所有数中(A和B的所有数)是第几小的数,对于B的每一个数,输出它们在所有数中是第几小的数
可以用两个指针分别遍历A和B中的每个数,然后两两比较,小的那个数就可以给它标记是第几小的数,双指针要注意边界问题,之前也做过类似的题目,经常搞不清边界,在这时就可以
用样例来试,发现如果A或B一边全部标记完了,那么剩下的就需要全部依次标记,可以将a[n+1]和b[m+1]初始化为超级大的数,这样的话,一边全部标记好之后,就可以把剩下的数依次标记了
注意while(l<=n||r<=m)用或而不是且
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int idxa[N],idxb[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
a[n+1]=1e9+10;
for(int i=1;i<=m;i++) cin>>b[i];
b[m+1]=1e9+10;
int l=1,r=1;
int idx=1;
while(l<=n||r<=m){
if(a[l]<b[r]){
idxa[l]=idx;
l++;
idx++;
}
else if(a[l]>b[r]){
idxb[r]=idx;
r++;
idx++;
}
}
for(int i=1;i<=n;i++) cout<<idxa[i]<<" ";
cout<<endl;
for(int i=1;i<=m;i++) cout<<idxb[i]<<" ";
cout<<endl;
return 0;
}
D - Bank
超时代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
const int N=5e5+10;
bool flag[N];//表示是否被呼叫过
set<int>s;
int main()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++) s.insert(i);
while(q--){
int op;
cin>>op;
if(op==1){
for(auto v:s){
if(!flag[v]){
flag[v]=true;
break;
}
}
}
else if(op==2){
int x;
cin>>x;
s.erase(x);
}
else{
for(auto v:s){
if(flag){
cout<<v<<endl;
break;
}
}
}
}
return 0;
}
实际上根本没必要用flag标记是否被呼叫过,如果是第一次被呼叫,那么直接将其放入set中,set中的就表示被呼叫过但没来的人,如果呼叫过然后来了的人就从set中删去
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
set<int>s;
int main()
{
int n,q;
cin>>n>>q;
int idx=1;
while(q--){
int op;
cin>>op;
if(op==1){
s.insert(idx);//表示被呼叫过但没来
idx++;
}
else if(op==2){
int x;
cin>>x;
s.erase(x);//被呼叫过然后来了的
}
else{
cout<<*s.begin()<<endl;
}
}
return 0;
}
E - 2xN Grid
大致题意是有一个行为2列为L的矩阵
这样输入:输入N1对数字(x,y),表示数字x有y个,依次填入第一行
同理,输入N2对数字(x,y),表示数字x有y个,依次填入第二行
最终,同一列的两个数字相等算一组,问一共有几组
首先,不能一个一个的填,因为L可以达到1e12,一个一个的填必定超时,共有N1+N2对,可以一对一对填,这样不会超时
然后填完之后,可以利用双指针进行判断,同时枚举上一边和下一边
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
int len,n1,n2;
cin>>len>>n1>>n2;
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
b.push_back({x,y});
}
int l=0,r=0;
int len1=a[0].second,len2=b[0].second;
int res=0;
if(a[0].first==b[0].first) res+=min(len1,len2);
while(len1<=len||len2<=len){
if(len1<=len2){
l++;
if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
len1+=a[l].second;
}
else{
r++;
if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
len2+=b[r].second;
}
}
cout<<res<<endl;
return 0;
}
进行改进:加上
if(len1==len&&len2==len) break;//如果双指针用while加if和else的话,最后不要忘记再加一句以退出循环
这样就没有RE了,此时还有点小错误,看来大方向是没问题的,只不过有一些小细节没有处理好,可能有特殊情况没有考虑到
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
int len,n1,n2;
cin>>len>>n1>>n2;
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
b.push_back({x,y});
}
int l=0,r=0;
int len1=a[0].second,len2=b[0].second;
int res=0;
if(a[0].first==b[0].first) res+=min(len1,len2);
while(len1<=len||len2<=len){
if(len1<=len2){
l++;
if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
len1+=a[l].second;
}
else{
r++;
if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
len2+=b[r].second;
}
if(len1==len&&len2==len) break;
}
cout<<res<<endl;
return 0;
}
再进行改进,依旧是对边界的改进,改完之后又对了一个测试点
if(len1<len) l++;
if(len2<len) r++;
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
int len,n1,n2;
cin>>len>>n1>>n2;
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
b.push_back({x,y});
}
int l=0,r=0;
int len1=a[0].second,len2=b[0].second;
int res=0;
if(a[0].first==b[0].first) res+=min(len1,len2);
while(len1<=len||len2<=len){
if(len1<=len2){
if(len1<len) l++;
if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
len1+=a[l].second;
}
else{
if(len2<len) r++;
if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
len2+=b[r].second;
}
if(len1==len&&len2==len) break;
}
cout<<res<<endl;
return 0;
}
此时样例错了一个,而且是样例二,第一行为1e10个1,第二行也为1e10个1
试了一下,发现res一开始+=1e10,然后len1变成了2e10,导致没有退出循环,后面res又加了,真是个巧合,这边可以避免len1变成2e10,即将res+=和len1+=都放到if(len1<len)里面
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
int len,n1,n2;
cin>>len>>n1>>n2;
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
b.push_back({x,y});
}
int l=0,r=0;
int len1=a[0].second,len2=b[0].second;
int res=0;
if(a[0].first==b[0].first) res+=min(len1,len2);
while(len1<=len||len2<=len){
if(len1<=len2){
if(len1<len) {
l++;
if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
len1+=a[l].second;
}
}
else{
if(len2<len) {
r++;
if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
len2+=b[r].second;
}
}
if(len1==len&&len2==len) break;
}
cout<<res<<endl;
return 0;
}
或者将len1==len改为大于等于
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
int len,n1,n2;
cin>>len>>n1>>n2;
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
b.push_back({x,y});
}
int l=0,r=0;
int len1=a[0].second,len2=b[0].second;
int res=0;
if(a[0].first==b[0].first) res+=min(len1,len2);
while(len1<=len||len2<=len){
if(len1<=len2){
if(len1<len) l++;
if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
len1+=a[l].second;
}
else{
if(len2<len) r++;
if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
len2+=b[r].second;
}
if(len1>=len&&len2>=len) break;
}
cout<<res<<endl;
return 0;
}
总的来说,一开始大致方向是对的,双指针主要难点在于处理边界问题