Bootstrap

2025 SUM-ACM 第二周周报

(年前年后的一块一起写了)(一些比较有意思的题在这里写一下)

Problem - B - Codeforces

题意

将一个长n的数组按顺序分成k个不为空的子数组,将所有第偶数个子数组合成一个数组并且在末尾加一个0,第一个数序号为1,定义此数组的代价为最小的 满足序号为i的数不等于i 的 i

输出最小的代价

思路

用贪心,希望第二的子数组的第一个数不是1,此时的代价就为1,为最小值

那如果前面有数为1,那么就划给第一个数组,注意第一个数组的最大长度为n-k+1

但实际上要求第二的数组的第一个数不为1就行,所以遍历前 n-k+1+1 个数来判断

如果前 n-k+1+1 个数都为1,此时分两种情况

第一种: n==k 此时每个数为一个子数组,取偶数位的数组成新数组按题意遍历找到满足要求的数就行

第二种: n>k 此时至少前三个数为1 ,将第一个1给第一个子数组,第二、第三个1 给第二个子数组,此时偶数数组的第二个数为1(不等于2)满足题意,代价为2,为当前情况下的最小值

(别走,看吐槽)

吐槽

注意特判前n-k+1+1个数中非1 的数是否只有一个并且是第一个数,如果是这种情况,按前 n-k+1+1 个数都为1 来处理,因为第一个子数组也不能为空

AC代码

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

#define int long long

int n,k;
int arr[200005];
int cha;

void solve(){
    int ans = 1e9+9;
   cin>>n>>k;
   cha = n-k+1;
   for(int i=1;i<=n;++i) cin>>arr[i];
   for(int i=n+1;i<=n+2;++i) arr[i]=0;
    for(int i=1;i<=cha+1;++i){
        if(arr[i]!=1 && i!=1){
            ans = min(ans,(long long)1);
            break;
        }
    }
    if(ans != 1){
        if(cha+1>=3){
            ans = min(ans,(long long)2);
        }
    }
    if(ans > 2){
        for(int i=2;i<=n+2;i+=2){
            if(arr[i]!=(i>>1)){
                ans = min(ans,(i>>1));
            }
        }
    }
    cout<<ans<<'\n';
}

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

PTA - 千手观音

题意

给出一些按升序排列的以字符串表示单个数字的数,求每个字符串(数)间的大小关系,无明确关系的按字典序顺序输出

思路

很明显是一个拓扑排序,同一层中的用一个优先队列来存就能实现按字典序输出

但拓扑排序的图怎么建出来呢?

这里我们明确一个大前提:

我们只能明确 两个位数相同且已知大小关系的的数中 从高位到低位 第一个不相同的数的大小关系

例如:

若 aa.ab.cc>aa.ac.bb 我们只能明确ab>ac

在这个大前提下对输入建图,我们就能进行拓扑排序得到答案了

吐槽

优先队列记得开成小根

AC代码

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

//#define int long long

int n;
string s;
vector<string> now,before;

unordered_map<string,vector<string> > adjacency_list;
priority_queue<string,vector<string>,greater<string> > pq;
unordered_map<string,int> indegree;

queue<string> ans;

vector<string> cut(string s){
    vector<string> res;
    string ss;
    for(int i=0;i<s.size();++i){
        if(s[i]!='.') ss+=s[i];
        else{
            res.push_back(ss);
            if(!indegree.count(ss)) indegree[ss]=0;
            ss.clear();
        }
    }
    if(!ss.empty()){
        res.push_back(ss);
        if(!indegree.count(ss)) indegree[ss]=0;
        ss.clear();
    }
    return res;
}


void solve(){
    cin>>n;
    cin>>s;
    before=cut(s);
    for(int i=1;i<n;++i){ //cout<<i;
        cin>>s;
        now = cut(s);
        if(before.size() == now.size()){
            for(int j=0;j<now.size();++j){
                if(before[j] != now[j]){
                    adjacency_list[before[j]].push_back(now[j]);
                    ++indegree[now[j]];
                    break;
                }
            }
        }
        before = now;
    }//邻接表建图↑
    //拓扑排序↓
    for(auto xx:indegree){
        if(xx.second==0) pq.push(xx.first);
    } //cout<<pq.size();
    while(!pq.empty()){
        s = pq.top();
        pq.pop();
        ans.push(s);
        for(auto xx:adjacency_list[s]){
            --indegree[xx];
            if(indegree[xx]==0) pq.push(xx);
        }
    } //cout<<ans.size();
    while(!ans.empty()){
        if(ans.size()==1){
            cout<<ans.front();
            return;
        }
        cout<<ans.front()<<".";
        ans.pop();
    }
}

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

;