Codeforces Round #780 (Div.3) A-F2 完整题解

好简单的一场,但我C题写了一小时,E题写了40min

我是啥b 总之开讲

 

A. Vasya and Coins

如果你没有硬币1,ans=1

否则ans=你的购买力+1

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int a[4][N];
int main(){
    int t;cin>>t;
    while(t--){
        int a,b;cin>>a>>b;
        if(a!=0)cout<<a+b+b+1<<'\n';
        else cout<<1<<'\n';
    }
}
View Code
复制代码

B. Vlad and Candies

theshy来全吃了

只吃最多的,而且不能连吃两个一样的

思考一下发现最大值与次大值相差小于1就行。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int a[N];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+n+1);    
        if(a[n]-a[n-1]<=1)cout<<"YES\n";
        else cout<<"NO\n";
    }
}
View Code
复制代码

C. Get an Even String

法1:贪心

扫一遍,谁先配上对就取那一对

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200007;
int main() {
    int t;cin>>t;
    int cnt[26];
    while (t--){
        memset(cnt,0,sizeof cnt);
        string s;cin>>s;
        int x=0;
        for(auto c:s){
            if(cnt[c-'a']){
                x+=2;for(int i=0;i<26;i++)cnt[i]=0;
            }
            else cnt[c-'a']++;
        }cout<<s.size()-x<<'\n';
    }
    return 0;
}
聪明人都写这种
复制代码

法2:dp 

啥B才写dp,比如我

考虑向右转移和向下一个相同字符(需要预处理)转移,同时把所有答案转移到n上作为结果

dp第二维的1表示这个字符消掉了,0表示没消掉

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int ne[N],dp[N][2];
queue<int>sx[26];
int main(){
    int t;cin>>t;
    while(t--){
        string s;cin>>s;
        int n=s.size();
        s=' '+s;
        for(int i=1;i<=n;i++){
            dp[i+1][0]=dp[i+1][1]=2e9;
            sx[s[i]-'a'].push(i);
        }dp[1][1]=1,dp[1][0]=0;
        for(int i=0;i<26;i++){
            while(!sx[i].empty()){
                int f=sx[i].front();sx[i].pop();
                if(sx[i].empty())break;
                ne[f]=sx[i].front();
            }
        }
        for(int i=1;i<=n;i++){
            dp[n][0]=min(dp[n][0],min(dp[i][0]+n+1-i,dp[i][1]+n-i));
            if(ne[i]!=0)dp[ne[i]][1]=min(dp[ne[i]][1],dp[i][0]+ne[i]-i-1);
            dp[i+1][0]=min({dp[i+1][0],dp[i][0]+1,dp[i][1]});
        }
        cout<<min(dp[n+1][1],dp[n+1][0])<<'\n';
        fill(ne,ne+n+3,0);
    }
}
别学,学了会变傻的
复制代码

D. Maximum Product Strikes Back

一段如果包含0,那它肯定不会大;所以把数组分成很多不含0的段

因为2的幂次不会减,对于每一段考虑贪心,如果整段乘起来大于零是最好的,否则分别不断去掉左(右)边的数,直到值变成正的。

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200007;
int a[N];
int zer[N],tot;//零的个数
int main() {
    int t;cin>>t;
    while (t--){tot=0;
        int n;cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];if(!a[i])zer[++tot]=i;
        }zer[++tot]=n+1;//0和-1的位置也要加上
        int al=0,ar=0,m=0;//左右端点,最大值的次数
        for(int i=1;i<=tot;i++){
            int ans=1,fh=1;//次数和符号
            for(int j=zer[i-1]+1;j<zer[i];j++){
                if(a[j]<0)fh*=-1;
                if(abs(a[j])>1)ans++;
            }
            if(fh>0&&m<ans)m=ans,ar=zer[i],al=zer[i-1];
            if(fh<0&&m<ans){
                int anss=ans;
                for(int j=zer[i-1];j<zer[i];j++){
                    if(abs(a[j])>1)anss--;
                    if(a[j]<0){
                        if(m<anss)m=anss,al=j,ar=zer[i];
                        break;
                    }
                }anss=ans;
                for(int j=zer[i]-1;j>zer[i-1];j--){
                    if(abs(a[j])>1)anss--;
                    if(a[j]<0){
                        if(m<anss)m=anss,ar=j,al=zer[i-1];
                    }
                }
            }
        }
        cout<<al<<' '<<n+1-ar<<'\n';
    }
    return 0;
}            
很暴力
复制代码

 E. Matrix and Shifts

容易发现四种操作本质上是一种操作

也就是说,一斜行的零变成1,其它斜行的1变成0。我们暴力一下就做完啦。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int a[N];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        fill(a,a+n+3,0);
        for(int i=1;i<=n;i++){
            string s;cin>>s;
            for(int j=1;j<=n;j++)a[(i-j+n)%n]+=s[j-1]-48;
        }int ans=0;
        for(int i=0;i<n;i++)ans+=a[i];
        int anss=n*n;
        for(int i=0;i<n;i++)anss=min(anss,ans-a[i]+n-a[i]);
        cout<<anss<<'\n';
    }
}
view shabby code
复制代码

F2&F1. Promising String 

我们令cnt值为子段中-的个数减去+的个数

每次操作少两个减号多一个加号,所以一个操作可以让cnt变成cnt-3;

我们不用考虑是否有相邻的-,因为我们只会去对cnt>=3的子段进行操作;这个时候必然有两个相邻的减号。

所以分别对于cnt模3余0、1、2的前缀,用树状数组操作一通就行了(我们只考虑cnt值小于等于当前cnt值的数,这是很经典的树状数组计数问题),复杂度O(nlogn)。

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200007;
int a[N];
int tr[N*2],n;
void add(int x){
    for(x=x+n+1;x<=n+n+2;x+=x&-x)tr[x]++;
}
ll qry(int x){ll r=0;
    for(x=x+n+1;x;x-=x&-x)r+=tr[x];
    return r;
}
int main() {
    int t;cin>>t;
    while (t--){cin>>n;
        string s;cin>>s;
        for(int i=1;i<=n;i++)a[i]=a[i-1]+((s[i-1]=='-')?1:-1);
        ll ans=0;
        for(int r=0;r<=2;r++){
            fill(tr,tr+2*n+5,0);
            if(r==0)add(0);
            for(int i=1;i<=n;i++)if((a[i]%3+3)%3==r)ans+=qry(a[i]),add(a[i]);
        }
        cout<<ans<<'\n';
    }
}
注意负数情况,树状数组要开两倍空间
复制代码

 

 

 

 

posted @   笨竹子  阅读(104)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示