Educational Codeforces Round 151 (Rated for Div. 2) A~D

 

A. Forbidden Integer

模拟:

void solve(){
int n,k,x;
cin>>n>>k>>x;
if(x!=1){
cout<<"YES\n"<<n<<"\n";
for(int i=1;i<=n;i++) cout<<"1"<<" \n"[i==n];
return ;
}
if(k==1){cout<<"NO\n";return ;}
if(k==2){
if(n%2==0){
cout<<"YES\n";
cout<<n/2<<"\n";
for(int i=1;i<=n/2;i++){
cout<<"2"<<" \n"[i==n/2];
}
}
else{
cout<<"NO\n";
}
return ;
}
if(n%2==0){
cout<<"YES\n";
cout<<n/2<<"\n";
for(int i=1;i<=n/2;i++){
cout<<"2"<<" \n"[i==n/2];
}
return ;
}
if(n-3>=0){
cout<<"YES\n";
int num=(n-3)/2;
cout<<(1+(n-3)/2)<<"\n";
for(int i=1;i<=num;i++){
cout<<2<<" ";
}
cout<<"3\n";
return ;
}
cout<<"NO\n";
}

B. Come Together

題目:两个人起初在一个坐标,各自用最短路移动到两个新的坐标,问最多一起走几个格子? 思路: 水平方向上的两个终点在起点的同侧,就可以一起走。模拟即可。 数值方向同理。

void solve(){
int x1,y1,x2,x3,y2,y3;
cin>>x1>>y1>>x2>>y2>>x3>>y3;
int ans=0;
if(x2>x1 && x3>x1){
ans+=min(x2,x3)-x1;
}
if(x2<x1 && x3<x1){
ans+=x1-max(x2,x3);
}
if(y2>y1 && y3>y1){
ans+=min(y2,y3)-y1;
}
if(y2<y1 && y3<y1){
ans+=y1-max(y2,y3);
}
ans+=1;
cout<<ans<<endl;
}

C. Strong Password

題目: 给一个序列s,还有两个长度都为m的串l,r..所有都是由0—9组成。 能不能构造一个密码:密码有m位,第i位的数字p 满足:l[i]<=p<=r[i] 思路: 从头开始遍历,模拟凑第一位,第二位到第m位,每一次得到每一位为了凑出所有可能情况最近需要到哪里,最后看如果在原先s里面能不能凑出来。 能凑出来,输出的是NO,因为还有一些题目背景,不再赘述。

需要实现一个功能: 现在某一位可能能取一些值,要找到这些值里面所有的最近的下一个位置。所有的最近的下一个位置取max。(就相当于我么可以在maxa的位置把前面的任何一种情况都凑出来)这里的凑出来,是指所有的情况都是目前串的一个subsequence. 序列自动机 代码:

bool solve(){
string s,s1,s2;
s=s1=s2="a";
int m;
string t; cin>>t;s+=t;
cin>>m;
cin>>t; s1+=t; cin>>t; s2+=t;
int len=s.size(); len--;
vector< array<int,10> >nx(len+5);
int ls[10];
memset(ls,0x3f3f3f3f,sizeof(ls));
nx[len+1].fill(len+1);
for(int i=len;i>=1;i--){
nx[i]=nx[i+1];
int loc=s[i]-'0';
nx[i][loc]=i;
// ls[loc]=i;
// for(int j=0;j<=9;j++){
// nx[i][j]=ls[j];
// }
}
int l=1;
for(int i=1;i<=m;i++){
if(l>len) return 1;
int num1=s1[i]-'0';
int num2=s2[i]-'0';
int maxa=0;
for(int j=num1;j<=num2;j++){
maxa=max(maxa,nx[l][j]);
}
if(i==m && maxa==len){
return 0;
}
l=maxa+1;
}
if(l<=len) return 0;
return 1;
}

序列自动机: nx[i][j]表示在第i个位置的右边,最近的j出现的位置是几? 有了nx数组之后也就相当于我们会知道在任意一个位置如果想要某一种字母、数字,需要到哪里才能凑到。 2022年上海市赛 子串也是类似的题目。

D. Rating System

题目: 给定n个数,现在value是0。遍历数组,每一次value+=a[i]。 我们可以规定一个东西:规定一个值k,如果value当前大于等于k,加上下一个数之后如果原本会小于k,那么他会等于k。 上面的操作只能进行一次,问value遍历一次数组之后得到的最后的最大值是几? 思路: 首先计算出前缀和数组,对于pre[i] 如果我们规定现在k就是pre[i] 那么计算pre[i+1]~pre[n]的最小值,答案会加上pre[i]-mina 对于上述思路,线段树维护区间min就可以解决。

思路2: CUP-PYY:

不难发现X一定是某个前缀和PRE[I]中的某个值.

不妨设X=pre[i],那么答案就是pre[i]加上suf[i+1∼n]这个序列的最大后缀,预处理出最大后缀然后枚举所有i更新答案即可.

const int N=3e5+6;
int tr[4*N];
int a[N],pre[N];
void build(int k,int l,int r){
if(l==r) {
tr[k]=pre[l];
return ;
}
int mid=(l+r)>>1;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tr[k]=min(tr[2*k],tr[2*k+1]);
}
long long  query(int k,int l,int r,int x,int y){
if(x<=l && r<=y) return tr[k];
int mid=(l+r)>>1;
int ans=0x3f3f3f3f3f3f3f3f;
if(x<=mid) ans=min(ans,query(2*k,l,mid,x,min(mid,y)) );
if(y>mid) ans=min(ans,query(2*k+1,mid+1,r,max(x,mid+1),y));
return ans;
}
void solve(){
int n;
cin>>n;
bool flag1=1;
bool flag2=1;
for(int i=1;i<=n;i++) {
cin>>a[i];
if(a[i]>0) flag1=0;
if(a[i]<0) flag2=0;
}
if(flag1==1 || flag2==1) {
cout<<"0"<<endl;
return ;
}
pre[0]=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+a[i];
  }
build(1,1,n);
int k=0;
int maxa=-0x3f3f3f3f3f3f3f3f;
maxa=max(maxa,pre[n]);
for(int i=0;i<n;i++){
int now=pre[i];
int mina=query(1,1,n,i+1,n);
int sum=pre[n]+(now-mina);
if(sum>maxa){
maxa=sum;
k=pre[i];
}
}
cout<<k<<endl;
}
 
posted @   橘赴亦梦人ω  阅读(164)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示