3.25-3.31週報

zyzzzzlh發表於2024-03-31

天梯賽2

7-10 紅色警報

這道題的題意要注意是刪去一個城市後增加了多少個區域,而不是有多少個城市變成了單獨的點,賽時理解錯了題意,用set做會有點有問題。其實很簡單,就是bfs搜一下有多少個聯通塊,每次刪除把被刪的點打個標記,每次聯通塊的個數和上一次的比較一下,只要增加就是改變了連通性,這樣判斷可以規避掉一開始就只有一個點單獨是一個聯通塊的情況。

點選檢視程式碼
void solve() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int ans;
    memset(vis,0,sizeof(vis));
    ans=0;
    for(int j=0;j<n;j++){
        if(vis[j]==1)
            continue;
        vis[j]=1;
        q.push(j);
        while(!q.empty()){
            auto x=q.front();
            q.pop();
            for(auto e:g[x]){
                if(vis[e])
                    continue;
                vis[e]=1;
                q.push(e);
            }
        }
        ans++;
    }
    //cout<<ans<<endl;
    int k;
    cin>>k;
    int ans1;
    for(int i=1;i<=k;i++){
        int d;
        cin>>d;
        f[d]=1;
        memset(vis,0,sizeof(vis));
        ans1=0;
        for(int j=0;j<n;j++){
            if(vis[j])
                continue;
            if(f[j])
                continue;
            vis[j]=1;
            q.push(j);
            while(!q.empty()){
                auto x=q.front();
                q.pop();
                for(auto e:g[x]){
                    if(vis[e])
                        continue;
                    if(f[e])
                        continue;
                    vis[e]=1;
                    q.push(e);
                }
            }
            ans1++;
        }
        //cout<<ans1<<endl;
        if(ans1>ans){
            cout<<"Red Alert: City "<<d<<" is lost!\n";
        }
        else{
            cout<<"City "<<d<<" is lost.\n";
        }
        ans=ans1;
    }
    if(k==n){
        cout<<"Game Over.\n";
    }
    return ;
}

7-15 特殊堆疊

這道題就是對頂堆,題意要中間的那個值,那就左右各開一個multiset,我只要保證左邊的數量最多比右邊多一個,要不就相等,那此時左邊的最後一個數就是結果。要注意multiset的語法規則,erase函式刪除某個數的話是把所有的都刪了,應該先用find函式找到它的位置再刪,erase函式也不能刪去rbegin要用end的prev

點選檢視程式碼
void tz(){
    int x1,x2;
    x1=s1.size(),x2=s2.size();
    if (x2 - x1 > 0) {
        int e = *(s2.begin());
        s2.erase(s2.begin());
        s1.insert(e);
    }
    if (x1 - x2 > 1) {
        int e = *(s1.rbegin());
        s1.erase(prev(s1.end()));
        s2.insert(e);
    }
    return ;
}

void solve() {
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        if(s=="Push"){
            int x;
            cin>>x;
            q.push(x);
            if(s1.empty()){
                s1.insert(x);
            }
            else {
                if (x >= *(s1.rbegin())) {
                    s2.insert(x);
                }
                else {
                    s1.insert(x);
                }
            }
            tz();
        }
        else if(s=="Pop"){
            if(q.empty()){
                cout<<"Invalid\n";
                continue;
            }
            int x=q.top();
            q.pop();
            cout<<x<<endl;
            //cout<<s1.size()<<" "<<s2.size()<<endl;
            //int e=*(s1.rbegin());
            auto ee=s1.find(x);
            if(ee!=s1.end()){
                s1.erase(ee);
            }
            else{
                s2.erase(s2.find(x));
            }
            tz();
        }
        else{
            if(q.empty()){
                cout<<"Invalid\n";
                continue;
            }
            cout<<*(s1.rbegin())<<endl;
        }

    }
    return ;
}

天梯賽3

7-7 連續因子

這道題其實就是暴力,因為要找連續因子,那不就是暴力迴圈起點,然後暴力向後迴圈,要注意第一維只要找到sqrt(n)就可以了,但是第二維不行,不過第二維最多12個,也無所謂。要注意本身是素數的情況。那就是全跑完了都沒找到因子。

點選檢視程式碼
void solve() {
    int n;
    cin>>n;
    int dans=0;
    int max1=0,l,d;
    
    for(int i=2;i*i<=n;i++){
        int x=n;
        int ans=0;
        if(x%i==0){
            ans++;
            x/=i;
            for(int j=i+1;j<=n;j++){
                if(x%j==0){
                    ans++;
                    x/=j;
                }
                else{
                    break;
                }
            }
            if(ans>max1){
                max1=ans;
                //dans=1;
                l=i;
            }
//            else if(ans==max1){
//                //dans++;
//            }
        }
    }
    if(max1==0){
        cout<<1<<endl;
        cout<<n<<endl;
        return ;
    }
    cout<<max1<<endl;
    for(int i=l;i<=l+max1-1;i++){
        cout<<i;
        if(i!=l+max1-1){
            cout<<"*";
        }
        else{
            cout<<"\n";
        }
    }
    return ;
}

7-9 哈利波特的考試

這道題一眼弗洛伊德,但怎麼會有人把板子敲錯啊。。。

就是純板子題,不放程式碼了。

7-11 病毒溯源

這道題我一看題面感覺很像並查集,因為保證了每個病毒都是由唯一的病毒變異而來,我就想著從每一個點開始去找祖先,看看誰最長,但是這個做法很暴力,直接執行超時,其實反過來想,這就是個樹啊,找最長鏈,那就是找到樹的根節點,然後計算每一個節點的深度。

點選檢視程式碼
void dfs(int x){
    if(dp[x]>max1){
        max1=dp[x];
        dd=x;
    }
    for(auto e:g[x]){
        dp[e]=dp[x]+1;
        dfs(e);
    }
}
void solve() {
    int n;
    cin>>n;
    for (int i = 0;i < n;i++){
        fa[i] = i;
    }
    for(int i=0;i<n;i++){
        int k;
        cin>>k;
        for(int j=1;j<=k;j++){
            int x;
            cin>>x;
            g[i].push_back(x);
            fa[x]=i;
        }
        sort(g[i].begin(),g[i].end());
    }
    int d;
    for(int i=0;i<n;i++){
        if(fa[i]==i){
            d=i;
            break;
        }
    }
    dp[d]=1;
    dfs(d);
    //cout<<d<<" "<<dd<<endl;
    vector<int>ve;
    while(1){
        if(dd==fa[dd])
            break;
        ve.push_back(dd);
        dd=fa[dd];
    }
    ve.push_back(d);
    int x=ve.size();
    cout<<x<<endl;
    for(int i=x-1;i>=0;i--){
        cout<<ve[i];
        if(i!=0){
            cout<<" ";
        }
        else{
            cout<<endl;
        }
    }
    return;
}