欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > Educational Codeforces Round 166

Educational Codeforces Round 166

2025/5/22 15:25:53 来源:https://blog.csdn.net/2301_79248730/article/details/144850684  浏览:    关键词:Educational Codeforces Round 166

Dashboard - Educational Codeforces Round 166

Problem - A - Codeforces

签到(写的有点烦…)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
void solve()
{int n;cin>>n;string s;cin>>s;vector<int>a;vector<char>b;vector<int>c;vector<char>d;s+='a';for(int i=0;i<n;i++){if(s[i]>='0'&&s[i]<='9'){a.push_back(int(s[i]-'0'));c.push_back(s[i]-'0');}else if(s[i]>='a'&&s[i]<='z'){b.push_back(s[i]);d.push_back(s[i]);if(s[i+1]>='0'&&s[i+1]<='9'){cout<<"NO"<<endl;return ;}}else {cout<<"NO"<<endl;return ;}}sort(a.begin(),a.end());sort(b.begin(),b.end());for(int i=0;i<int(a.size());i++){if(a[i]!=c[i]){cout<<"NO"<<endl;return ;}}for(int i=0;i<b.size();i++){if(b[i]!=d[i]){cout<<"NO"<<endl;return ;}}cout<<"YES"<<endl;
}
int main()
{int t;cin>>t;while(t--)solve();
}

Problem - B - Codeforces

遍历 1 ≤ i ≤ n 1\leq i\leq n 1in

显然初始答案为 1 + ∑ 1 ≤ i ≤ n a b s ( a [ i ] − b [ i ] ) 1+\sum_{1\leq i\leq n}abs(a[i]-b[i]) 1+1inabs(a[i]b[i])

如果存在一个 i i i使得 b [ n + 1 ] b[n+1] b[n+1] a [ i ] a[i] a[i] b [ i ] b[i] b[i]之间,那么答案就是上述和

否则还要加上 m i n ( m i n ( a b s ( b [ n + 1 ] − a [ i ] ) , a b s ( b [ n + 1 ] − b [ i ] ) ) 1 ≤ i ≤ n ) min(min(abs(b[n+1]-a[i]),abs(b[n+1]-b[i]))1\leq i\leq n) min(min(abs(b[n+1]a[i]),abs(b[n+1]b[i]))1in)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int b[N];
void solve()
{int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n+1;i++)scanf("%d",&b[i]);long long ans=0;int f=2e9;for(int i=1;i<=n;i++){ans+=abs(a[i]-b[i]);int x=min(a[i],b[i]);int y=max(a[i],b[i]);if(b[n+1]>=x&&b[n+1]<=y)f=0;else{if(f){int p=min(abs(x-b[n+1]),abs(y-b[n+1]));f=min(f,p);}}}cout<<ans+1+f<<endl;
}
int main()
{int t;cin>>t;while(t--)solve();
}

Problem - C - Codeforces

数学 前缀和

感觉好烦,我写的也好烦…

一个公司要招聘 n n n个A职位和 m m m个B职位,共有 n + m + 1 n+m+1 n+m+1人来应聘

一个人的能力值由 a [ i ] , b [ i ] a[i],b[i] a[i],b[i]构成, a [ i ] ! = b [ i ] a[i]!=b[i] a[i]!=b[i]

面试到第 i i i人时候,除去 i i i,其余人从前往后遍历,若 a [ i ] > b [ i ] a[i]>b[i] a[i]>b[i]且A职位有空余则将该人设为A职位,否则便是B职位

求出此时所有人的对应能力之和(为A职位则加 a [ i ] a[i] a[i])

由于是从前往后遍历的,所以想到可以用前缀和来处理

开两个数组 a a , b b aa,bb aa,bb分别存储 a [ i ] > b [ i ] a[i]>b[i] a[i]>b[i] a [ i ] < b [ i ] a[i]<b[i] a[i]<b[i]的下标

然后分别计算这两个数组的 a i a_i ai的前缀和与 b i b_i bi的前缀和

开始遍历职员,遍历到 i i i时,设 x , y x,y x,y为除去 i i i之外的 a [ i ] > b [ i ] , a [ i ] < b [ i ] a[i]>b[i],a[i]<b[i] a[i]>b[i],a[i]<b[i]的人数,设 s u m = ∑ m a x ( a [ i ] , b [ i ] ) sum=\sum max(a[i],b[i]) sum=max(a[i],b[i])

x = a a . s i z e ( ) − ( a [ i ] > b [ i ] ? 1 : 0 ) x=aa.size()-(a[i]>b[i]? 1:0) x=aa.size()(a[i]>b[i]?1:0)

$ y=bb.size()-(b[i]>a[i]?1:0)$

先判断职位是否会出现不平衡,如果 x = = n x==n x==n则不会出现不平衡, a n s = s u m − m a x ( a [ i ] , b [ i ] ) ans=sum-max(a[i],b[i]) ans=summax(a[i],b[i])

否则,分为两种情况,处理方法相同,这里就说下 x > n x>n x>n

由于是顺序遍历,所以会有 x − n x-n xn个原本 a [ i ] > b [ i ] a[i]>b[i] a[i]>b[i]的人要分配到B职位

p = a a [ a a . s i z e ( ) − ( x − n ) ] p=aa[aa.size()-(x-n)] p=aa[aa.size()(xn)],即为这个分界线,要将 p p p(包含 p p p)右边的人的和换成 b [ i ] b[i] b[i]

此处还要讨论一下,如果 a [ i ] > b [ i ] a[i]>b[i] a[i]>b[i]的话,可能目前的这个 i i i还包含在 p p p的右边,要特判一下,包含的话要将 p p p再左移一位

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int b[N];
int n,m;
long long l[N],r[N],ll[N],rr[N];
void solve()
{scanf("%d%d",&n,&m);for(int i=1;i<=n+m+1;i++){scanf("%d",&a[i]);}for(int i=1;i<=n+m+1;i++){scanf("%d",&b[i]);}vector<int>aa;vector<int>bb;long long sum=0;aa.push_back(11);bb.push_back(11);//处理前缀和下标最好从1开始for(int i=1;i<=n+m+1;i++){if(a[i]>b[i]){aa.push_back(i);}else bb.push_back(i);sum+=max(a[i],b[i]);}for(int i=1;i<=aa.size()-1;i++){ll[i]=ll[i-1]+a[aa[i]];l[i]=l[i-1]+b[aa[i]];}for(int i=1;i<=bb.size()-1;i++){rr[i]=rr[i-1]+b[bb[i]];r[i]=r[i-1]+a[bb[i]];}for(int i=1;i<=n+m+1;i++){int x=aa.size()-1,y=bb.size()-1;if(a[i]>b[i])x--;else y--;if(x==n){cout<<sum-max(a[i],b[i])<<' ';}else{if(x>n){int f=x-n;int p=aa.size()-1-f;if(a[i]>b[i]){if(aa[p]<i){p--;cout<<sum-(ll[aa.size()-1]-ll[p])+l[aa.size()-1]-l[p]-b[i]<<' ';}elsecout<<sum-(ll[aa.size()-1]-ll[p])+l[aa.size()-1]-l[p]-a[i]<<' ';}elsecout<<sum-max(a[i],b[i])-(ll[aa.size()-1]-ll[p])+l[aa.size()-1]-l[p]<<' ';}else{int f=y-m;int p=bb.size()-1-f;if(a[i]<b[i]){if(bb[p]<i){p--;cout<<sum-(rr[bb.size()-1]-rr[p])+r[bb.size()-1]-r[p]-a[i]<<' ';}elsecout<<sum-(rr[bb.size()-1]-rr[p])+r[bb.size()-1]-r[p]-b[i]<<' ';}elsecout<<sum-max(a[i],b[i])-(rr[bb.size()-1]-rr[p])+r[bb.size()-1]-r[p]<<' ';}}}cout<<endl;
}
int main()
{int t;cin>>t;while(t--)solve()

Problem - D - Codeforces

好难…

栈 RMQ 前缀和

对于一段括号序列(只包含"()"),

有一个小 t r i c k trick trick就是将 ′ ( ′ , ′ ) ′ '(',')' (,)设为 1 , − 1 1,-1 1,1,设 p r e [ i ] = ∑ 1 ≤ k ≤ i ( s [ i ] = = ′ ( ′ ? 1 : − 1 ) pre[i]=\sum_{1\leq k \leq i}(s[i]=='('? 1:-1) pre[i]=1ki(s[i]==(?1:1)

如果这段序列满足

∀ i ∈ [ 1 , n ] , p r e [ i ] ≥ 0 \forall i \in [1,n] ,pre[i]\geq 0 i[1,n]pre[i]0

s [ n ] = = 0 s[n]==0 s[n]==0

则这段序列为一个有效匹配

现在给出一个有效匹配序列,找出所有的 1 ≤ l ≤ r ≤ n 1\leq l\leq r\leq n 1lrn,将 [ l , r ] [l,r] [l,r]内的序列翻转,‘(‘变为’)’,‘(‘变为’)’,使得翻转后的序列仍然为一个有效匹配

按照套路,可以枚举左端点(左右都可以),看看右边有哪些可以和它匹配的

对于一个左端点 l l l,假设找到一个右端点 k k k,首先肯定要满足翻转之后左右括号的数量仍然相等,即 p r e k − p r e l − 1 = 0 , p r e k = p r e l − 1 pre_{k}-pre_{l-1}=0,pre_{k}=pre_{l-1} prekprel1=0,prek=prel1

固定左端点,找到满足这个条件的 k k k可以开一个 m a p < i n t , v e c t o r < i n t > > map<int,vector<int>> map<int,vector<int>>,存储每个前缀和对应的下标,二分出大于等于 l l l的最小下标 x x x即可

但是这样只满足了第二个条件,在翻转过程中可能出现 p r e i < 0 pre_i<0 prei<0的情况

p r e l − 1 pre_{l-1} prel1是不会变化的,而 p r e k = p r e l − 1 − ( p r e k − p r e l − 1 ) = 2 ∗ p r e l − 1 − p r e k pre_{k}=pre_{l-1}-(pre_k-pre_{l-1})=2*pre_{l-1}-pre_k prek=prel1(prekprel1)=2prel1prek

要满足 [ l , k ] [l,k] [l,k]内的所有的前缀和都大于等于零,有 ∀ j ∈ [ l , k ] , 2 ∗ p r e l − 1 − p r e j ≥ 0 , 2 ∗ p r e l − 1 ≥ m a x ( p r e j ) \forall j \in [l,k],2*pre_{l-1}-pre_j\geq 0,2*pre_{l-1}\geq max(pre_j) j[l,k],2prel1prej0,2prel1max(prej)

由于固定了 l l l,这里的 m a x ( p r e k ) , l ≤ k ≤ n max(pre_k),l\leq k \leq n max(prek),lkn是单调不减的,可以先利用 S T ST ST表处理每段区间的最大值,然后二分出满足 m a x ( p r e k ) ≤ 2 ∗ p r e l − 1 , l ≤ k ≤ r max(pre_k)\leq 2*pre_{l-1},l\leq k\leq r max(prek)2prel1lkr的最大的 r r r,这样的话 [ l , r ] [l,r] [l,r]内的值便都满足了第一个条件,再二分出小于等于 r r r的最大下标 y y y,让答案加上 y − x + 1 y-x+1 yx+1即可

这里不用特判一下 y ≥ x y\geq x yx,因为只存在一种 y < x y<x y<x,就是 x , y x,y x,y都返回了 e n d end end,此时 y = x − 1 , y − x + 1 = 0 y=x-1,y-x+1=0 y=x1yx+1=0

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int f[N][20],lg[N];
int n;
string s;
int query(int l,int r)
{int k=lg[r-l+1];return max(f[l][k],f[r-(1<<k)+1][k]);
}
void solve()
{cin>>s;s=' '+s;int n=s.length()-1;long long ans=0;map<int,vector<int>>mp;for(int i=1;i<=n;i++){f[i][0]=f[i-1][0]+(s[i]=='('? 1:-1);mp[f[i][0]].push_back(i);}for(int j=1;j<=lg[n];j++){for(int i=1;i<=n-(1<<j)+1;i++){f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);}}for(int i=1;i<=n-1;i++){int l=i,r=n;while(l<r){int mid=(l+r+1)>>1;if(query(i,mid)<=2*f[i-1][0])l=mid;else r=mid-1;}if(query(i,l)>2*f[i-1][0])continue;int x=lower_bound(mp[f[i-1][0]].begin(),mp[f[i-1][0]].end(),i)-mp[f[i-1][0]].begin();int y=upper_bound(mp[f[i-1][0]].begin(),mp[f[i-1][0]].end(),r)-mp[f[i-1][0]].begin()-1;//小于等于ans+=(y-x+1);}cout<<ans<<endl;
}
int main()
{for(int i=2;i<=N-10;i++)lg[i]=lg[i>>1]+1;int t;cin>>t;while(t--)solve();
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com