20240810
赛时得分
| 题目 | A | B | C | D | 总分 | 排名 | 比例 |
|---|---|---|---|---|---|---|---|
| 满分 | 100 | 100 | 100 | 100 | 400 | 165 | 100% |
| 得分 | 40 | 0 | 41 | 0 | 81 | 127 | 77.0% |
A. 括号翻转(80/100)
\(\text{80%}\) 得分做法,遇到这种括号匹配题直接用一个 stack 统计左括号位置,压入进去,当找到最近的右括号时,我们就把栈顶的左括号坐标拉出来和当前右括号坐标组成一个 pair 压入一个 vector 中。然后对于每一对括号,我们模拟把他所包含的字符串反转,这里要记住,reverse 函数是可以完成一个串内的部分反转的。如果我们想反转一个串 \(s\) 从 \(l\) 到 \(r\) 的部分,我们只需要调用 reverse(s.begin()+l,s.begin()+r+1) 即可。最后我们遍历一遍串,遇到括号不输出,就结束了。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
string s;
vector<pair<ll,ll> > v;
stack<ll> st;
int main()
{
freopen("bracket.in","r",stdin);
freopen("bracket.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>s;
for(ll i=0;i<s.length();i++)
{
if(s[i]=='(') st.push(i);
else if(s[i]==')')
{
v.push_back({st.top(),i});
st.pop();
}
}
for(auto i:v) reverse(s.begin()+i.first+1,s.begin()+i.second);
for(int i=0;i<s.length();i++)
{
if(s[i]=='(' or s[i]==')') continue;
else cout<<s[i];
}
return 0;
}
B. 相交(100/100)
赛时 sb 到连这个 20 分都写寄了。\(\text{20%}\) 得分做法,一条链的特性,实际上直接判断两个区间有没有交点即可。结果我修改 \(\max\) 和 \(\min\) 值的时候忘记拉第三方了。
\(\text{50%}\) 得分做法,由于树上两点之间只有一条路径,我们进行一个 dfs,利用一个 stack 维护出经过的所有点的编号,扔到两个 set 中对比一下就可以了。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=1e5+1;
ll n,u,v,a,b,c,d,q,s,t;
vector<ll> e[N];
stack<ll> st,ins;
set<ll> s1,s2;
bool ok,pd1=1;
void dfs1(ll x,ll fa)
{
st.push(x);
if(x==b)
{
ins=st;
while(!st.empty())
{
s1.insert(st.top());
st.pop();
}
st=ins;
}
for(auto y:e[x])
{
if(y!=fa) dfs1(y,x);
}
st.pop();
return;
}
void dfs2(ll x,ll fa)
{
st.push(x);
if(x==d)
{
ins=st;
while(!st.empty())
{
s2.insert(st.top());
st.pop();
}
st=ins;
}
for(auto y:e[x])
{
if(y!=fa) dfs2(y,x);
}
st.pop();
return;
}
void sub()
{
cin>>q;
while(q--)
{
ll aa,bb,cc,dd;
cin>>a>>b>>c>>d;
aa=min(a,b),bb=max(a,b);
cc=min(c,d),dd=max(c,d);
if(cc>bb or dd<aa) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return;
}
int main()
{
freopen("ant.in","r",stdin);
freopen("ant.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<n;i++)
{
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
if(min(u,v)!=i or max(u,v)!=i+1) pd1=0;
}
if(pd1==1)
{
sub();
return 0;
}
cin>>q;
while(q--)
{
cin>>a>>b>>c>>d;
ok=0,s1.clear(),s2.clear();
dfs1(a,0);
dfs2(c,0);
for(auto i:s1)
{
if(s2.find(i)!=s2.end())
{
ok=1;
break;
}
}
if(ok==0) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
\(\text{100%}\) 得分做法,考虑经典问题,想判断树上两条路径 \(p_1,p_2\) 是否相交,我们需要求得 \(p_1,p_2\) 的 \(lca_1,lca_2\),若 \(lca_1\) 在 \(p_2\) 上或 \(lca_2\) 在 \(p_1\) 上,那么两条路径就是相交的。那么,想判断一个点 \(x\) 是否在以 \(s,t\) 为起点终点的一条路径上,我们只需要判断 \(dis_{x,s}+dis_{x,t}\) 是否等于 \(dis_{s,t}\) 即可,其中 \(dis\) 表示树上两点间距离。
我们用 LCA 求得两点间距离,即可 \(\text{O(1)}\) 进行查询。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=2e5+1;
ll n,q,u,v,a,b,s,t,d[N],p[N][21],lca1,lca2;
vector<ll> e[N];
void dfs(ll x,ll fa)
{
d[x]=d[fa]+1;
p[x][0]=fa;
for(int i=1;(1<<i)<=d[x];i++) p[x][i]=p[p[x][i-1]][i-1];
for(auto y:e[x])
{
if(y!=fa) dfs(y,x);
}
return;
}
ll lca(ll a,ll b)
{
if(d[a]>d[b]) swap(a,b);
for(int i=20;i>=0;i--)
{
if(d[a]<=d[b]-(1<<i)) b=p[b][i];
}
if(a==b) return a;
for(int i=20;i>=0;i--)
{
if(p[a][i]==p[b][i]) continue;
else a=p[a][i],b=p[b][i];
}
return p[a][0];
}
ll getdis(ll s,ll t)
{
return d[s]+d[t]-2*d[lca(s,t)];
}
bool pd(ll x,ll s,ll t)
{
if(getdis(s,x)+getdis(x,t)==getdis(s,t)) return 1;
else return 0;
}
int main()
{
freopen("ant.in","r",stdin);
freopen("ant.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<n;i++)
{
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0);
cin>>q;
while(q--)
{
cin>>a>>b>>s>>t;
lca1=lca(a,b),lca2=lca(s,t);
if(pd(lca1,s,t)==1 or pd(lca2,a,b)==1) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
C. 排列盒子(41/100)
\(\text{41%}\) 得分做法,首先统计原序列中各元素的数量,然后用 next_permutation 枚举全排列,再将排列中元素个数变成统计的数量,也就可以得到所有的答案序列。对于每一种答案序列我们从左到右枚举处理,每处理完一个序列我们就将他放在前面,统计一下所有处理过程中的答案最小值即可。
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=1e5+1;
ll n,k,f[N],pos,cnt1,cnt2,cnt[N],a[N];
ll ans=2147483648,stp,p[N],x,ins[N],res,ins2[N],cntt;
void sub1()
{
string ak="";
for(int i=1;i<=n;i++)
{
cin>>f[i];
if(f[i]==1) ak+="1";
else ak+="2";
}
for(int i=0;i<ak.length();i++)
{
if(ak[i]=='1')
{
cnt1=cnt1+(i-pos);
pos++;
}
}
pos=0;
for(int i=0;i<ak.length();i++)
{
if(ak[i]=='2')
{
cnt2=cnt2+(i-pos);
pos++;
}
}
cout<<min(cnt1,cnt2);
return;
}
int main()
{
freopen("box.in","r",stdin);
freopen("box.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
if(k==2)
{
sub1();
return 0;
}
for(int i=1;i<=n;i++)
{
cin>>f[i];
cnt[f[i]]++;
}
for(int i=1;i<=k;i++) a[i]=i;
do
{
stp=0,x=1,res=1,cntt=0;
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++) ins[i]=f[i];
for(int i=1;i<=k;i++)
{
for(int j=1;j<=cnt[a[i]];j++) p[x++]=a[i];
}
for(int j=1;j<=k;j++)
{
for(int i=1;i<=n;i++)
{
if(ins[i]==a[j])
{
stp+=(i-res);
res++;
}
}
cntt=0;
memset(ins2,0,sizeof(ins2));
for(int i=1;i<=cnt[a[j]];i++) ins2[++cntt]=a[j];
for(int i=1;i<=n;i++)
{
if(ins[i]!=a[j]) ins2[++cntt]=ins[i];
}
for(int i=1;i<=n;i++) ins[i]=ins2[i];
}
ans=min(ans,stp);
}while(next_permutation(a+1,a+k+1));
cout<<ans;
return 0;
}

浙公网安备 33010602011771号