left 2 Codeforces Round 916 (Div. 3)

题目链接

A.

遍历字符串,用map记录下每个字符出现的次数
最后遍历26个字母,若出现了相应次数答案+1

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=1e5+10;

void solve() {
    int n;cin>>n;
    string s;cin>>s;
    map<char,int>mp;
    for(int i=0;i<s.size();i++){
        mp[s[i]]++;
    }
//    for(auto t:mp){
//        cout<<t.first<<' '<<t.second<<'\n';
//    }
    int ans=0;
    for(int i=0;i<26;i++){
        if(mp[(char)('A'+i)]>=i+1)ans++;
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

B.

升序能让他兴奋,倒序不会
让k+1是升序的,剩下的倒序

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=1e5+10;

void solve() {
    int n,k;cin>>n>>k;
    int tmp=n-k;
    for(int i=tmp;i<=n;i++)cout<<i<<' ';
    for(int i=tmp-1;i>=1;i--)cout<<i<<' ';
    cout<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

C.

枚举+贪心
初步思路一直想着一次贪完,发现无法做
然后考虑枚举+贪心
枚举的是要顺序完成几个任务,贪心的是维护b数组的最大值
去掉顺序完成任务的必须天数,剩下的全部去完成最大值

debug:
注意k和n的大小关系,可能枚举不完

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=1e5+10;

void solve() {
    int n,k;cin>>n>>k;
    vector<int>a(n+1),b(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    int ans=0,ma=0,pre=0,tmp;
    for(int i=1;i<=min(n,k);i++){
        ma=max(ma,b[i]);
        tmp=pre+a[i]+max(0ll,(k-i)*ma);
        ans=max(ans,tmp);
        pre+=a[i];
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

D.

枚举+贪心
贪心:若我们选择了一天,那么这一天一定是可选的天数中a或b或c最大的那一天
枚举:a优先再b优先再c优先
a优先再c优先再b优先
......
3的全排列

也就是按a优先的前3个与b的前3个,c的前3个的全排列

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=1e5+10;

struct node{
    int a,b,c;
}g[N];
bool cmp1(node x,node y){
    return x.a>y.a;
}
bool cmp2(node x,node y){
    return x.b>y.b;
}
bool cmp3(node x,node y){
    return x.c>y.c;
}
void solve() {
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>g[i].a;
    for(int i=1;i<=n;i++)cin>>g[i].b;
    for(int i=1;i<=n;i++)cin>>g[i].c;
    int ma=0,tmp=0;
    sort(g+1,g+1+n,cmp1);
    tmp+=g[1].a;
    sort(g+2,g+1+n,cmp2);
    tmp+=g[2].b;
    sort(g+3,g+1+n,cmp3);
    tmp+=g[3].c;
    ma=max(ma,tmp);
    tmp=0;
    sort(g+1,g+1+n,cmp1);
    tmp+=g[1].a;
    sort(g+2,g+1+n,cmp3);
    tmp+=g[2].c;
    sort(g+3,g+1+n,cmp2);
    tmp+=g[3].b;
    ma=max(ma,tmp);
    tmp=0;
    sort(g+1,g+1+n,cmp2);
    tmp+=g[1].b;
    sort(g+2,g+1+n,cmp1);
    tmp+=g[2].a;
    sort(g+3,g+1+n,cmp3);
    tmp+=g[3].c;
    ma=max(ma,tmp);
    tmp=0;
    sort(g+1,g+1+n,cmp2);
    tmp+=g[1].b;
    sort(g+2,g+1+n,cmp3);
    tmp+=g[2].c;
    sort(g+3,g+1+n,cmp1);
    tmp+=g[3].a;
    ma=max(ma,tmp);
    tmp=0;
    sort(g+1,g+1+n,cmp3);
    tmp+=g[1].c;
    sort(g+2,g+1+n,cmp1);
    tmp+=g[2].a;
    sort(g+3,g+1+n,cmp2);
    tmp+=g[3].b;
    ma=max(ma,tmp);
    tmp=0;
    sort(g+1,g+1+n,cmp3);
    tmp+=g[1].c;
    sort(g+2,g+1+n,cmp2);
    tmp+=g[2].b;
    sort(g+3,g+1+n,cmp1);
    tmp+=g[3].a;
    ma=max(ma,tmp);
    tmp=0;
    cout<<ma<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

E.

贪心地想,有两种情况:
自己得的多但对方丢的少,自己得的少但对方丢的多
如何合并?
把自己得的和对方丢的都算自己得的即可
由题意可知,一种颜色只会由一个人操作,而不管由谁操作得到的总贡献是一样的
那么我们直接按贡献排个序,再按轮次记录下两人实际得到的弹珠数,最终结果相减即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=1e5+10;

struct node{
    int sum,a,b;
};
bool cmp(node x,node y){
    return x.sum>y.sum;
}
void solve() {
    int n;cin>>n;
    vector<int>a(n+1),b(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    vector<node>g(n+1);
    for(int i=1;i<=n;i++){
        g[i].sum=a[i]+b[i]-1;
        g[i].a=a[i];g[i].b=b[i];
    }
    sort(g.begin()+1,g.end(),cmp);
    int alice=0,bob=0;
    for(int i=1;i<=n;i++){
        if(i&1){
            alice+=g[i].a-1;
        }else{
            bob+=g[i].b-1;
        }
    }
    cout<<alice-bob<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

F.

把题目所给的关系看成一棵树
也就是从根节点到叶子结点的简单路径上的点不能组队
其特点是只有叶子节点的出度为0
那么我们每次找两个叶子结点组队即可
可以先预处理出每个节点的深度,深度大的优先组队

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=2e5+10;

int n;
vector<int>g[N];
int f[N],out[N],dep[N];
void dfs(int u,int step){
    dep[u]=step;
    for(int t:g[u])dfs(t,step+1);
}
void solve() {
    cin>>n;
    vector<int>p(n+2);
    for(int i=2;i<=n;i++){
        cin>>f[i];
        g[f[i]].push_back(i);
        out[f[i]]++;
    }
    dfs(1,1);
    priority_queue<pair<int,int>>q;
    for(int i=1;i<=n;i++){
        if(out[i]==0)q.push({dep[i],i});
    }
    int ans=0;
    while(q.size()>=2){
        auto x=q.top();q.pop();
        auto y=q.top();q.pop();
        ans++;
        if(--out[f[x.second]]==0&&f[x.second]!=1){
            q.push({dep[f[x.second]],f[x.second]});
        }
        if(--out[f[y.second]]==0&&f[y.second]!=1){
            q.push({dep[f[y.second]],f[y.second]});
        }
    }
    cout<<ans<<'\n';
    for(int i=1;i<=n;i++){
        g[i].clear();
        f[i]=0;out[i]=0;dep[i]=0;
    }
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

G1/G2.

先考虑S集合的最小大小
自己思路是遇到不同颜色的灯泡tmp值+1,遇到相同颜色灯泡tmp值-1,党tmp为0时说明不能再拓展了
题解提供了异或的方法,两个相同的数异或为0
所以这个过程可以用异或来代替
异或还有个好处是两个相同的数异或才为0
而加加减减没有辨识度

再考虑连通块内部的小连通块
这其实是局部区间消除,那么我们可以记录异或前缀
若有相同的出现,把这段标记
最后统计答案时不再统计这段即可

这里吧1-n用随机数去映射,可以降低哈希冲突

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N=2e5+10;

const int mod=998244353;
mt19937_64 rnd(98275314);
int get(){
    int x=0;
    while(x==0)x=rnd();
    return x;
}
vector<int>c,g;
int block(int l,int r){
    int ans=0;
    while(l<r){
        if(g[l]!=-1&&g[l]<r){
            l=g[l];
        }else {
            ans++;
            l++;
        }
    }
    return ans;
}
void solve() {
    int n;cin>>n;
    int size=0,cnt=1;
    c.resize(n*2);
    g.resize(n*2,-1);
    for(int i=0;i<2*n;i++){
        cin>>c[i];c[i]--;
    }
    vector<int>val(n);
    for(int i=0;i<n;i++)val[i]=get();
    map<int,int>last;
    int cur=0;
    last[0]=0;
    for(int i=0;i<n*2;i++){
        cur^=val[c[i]];
        if(cur==0){
            size++;
            cnt=(cnt* block(last[0],i+1))%mod;
            last.clear();
        }else if(last.count(cur))g[last[cur]]=i+1;
        last[cur]=i+1;
    }
    cout<<size<<' '<<cnt<<'\n';
    c.clear();g.clear();
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int left=1;
    cin>>left;
    while(left--){
        solve();
    }
}

posted @ 2024-02-03 15:17  WW爆米花  阅读(6)  评论(0编辑  收藏  举报