AtCoder Beginner Contest 173 題解


AtCoder Beginner Contest 173 題解

A - Payment

首先我們可以把所有不用找零的部分都付掉,這樣就只剩下了\(A \mod 1000\)這樣一個“\(A\)除以\(1000\)的余數部分”。

然后我們再來用\(1000\)減去它,就是要找的零錢,但是假如剛好余數為\(0\)就會出鍋,所以再要特判一下,程序這里直接寫進公式里了:

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

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n;
    cin>>n;
    cout<<(1000-n%1000)%1000<<endl;

    return 0;
}

B - Judge Status Summary

這波啊,這波是小學數數(霧)。這就是普通的計數啊,我們可以使用C++的STL中的一位:map

這里講了map的使用方法:OI-wiki

然后你建立一個字符串對應到整數的map,然后每次讀入一個字符串都把對應值加一就行。然后輸出每個狀態對應的值就好。

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

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    map<string,int> mp;
    string s;
    int n;
    cin>>n;
    while(n--){
        cin>>s;
        mp[s]++;
    }
    cout<<"AC x "<<mp["AC"]<<'\n';
    cout<<"WA x "<<mp["WA"]<<'\n';
    cout<<"TLE x "<<mp["TLE"]<<'\n';
    cout<<"RE x "<<mp["RE"]<<'\n';

    return 0;
}

C - H and V

很顯然數據這么小,我們可以枚舉哪些列需要塗色,然后再計算沒有塗過的黑色塊就好了。

這里你需要學習狀態壓縮來更好地枚舉塗色的列的集合,你可以把集合壓縮成一個整數,當中對應的位為\(1\)表示這一行/列塗色了,否則沒有塗。這里來學習位運算狀態壓縮(狀壓DP順便也看看吧,會有用的)。

我這里設置了第\(1\)\(H\)的二進制位表示對應的行的狀態,同理第\(H+1\)\(W\)位表示對應的列的狀態。

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

int h,w,k;
char g[10][10];

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>h>>w>>k;
    for(int i=0;i<h;i++){
        cin>>g[i];
    }
    int ans=0;
    for(int s=0;s<1<<h+w;s++){//先執行+再執行<<,A<<B表示A*2^B
        int c=0;
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                c+=!(s>>i&1)&&!(s>>h>>j&1)&&g[i][j]=='#';//先執行>>再執行&,A>>B&1表示A的第B位,值是1或0
            }
        }
        ans+=c==k;
    }
    cout<<ans<<endl;

    return 0;
}

D - Chat in a Circle

首先我們先把\(A\)從大到小排列一下,並從前往后地讓對應位置的人進圈。感性地想,讓權值高的人先進,就可以影響旁邊人的心情更好,可以證明是對的,但我不會qaq。

然后容易看出,除了第一個人只能影響第二個之外,其余的人都有兩個可以影響的空位(廢話,左右兩邊各一個,寫題解的人腦子有病吧)。然后就好了可以寫程序了(

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

int n;
int a[200005];

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    sort(a,a+n,[](const int &a,const int &b){
        return a>b;
    });
    int tot=n-1;
    long long ans=0;
    for(int i=0;i<n;i++){
        if(tot){
            ans+=a[i];
            tot--;
        }
        if(tot&&i){
            ans+=a[i];
            tot--;
        }
    }
    cout<<ans<<endl;

    return 0;
}

E - Multiplication 4

我們先判斷一下能不能弄出一個正的乘積啊,然后退而求其次看能不能弄出\(0\)來,最后再盡量弄一個絕對值小的負數乘積啊。

假如負數兩兩一對,加上一部分正數能夠湊到\(K\)個,就可以弄出正的乘積了。

先看正的乘積,我們把正數負數絕對值從大到小排序,然后兩兩一對乘起來。然后盡量取大的一對乘起來,最后假如\(K\)是奇數就添上一個單獨的正數就好了啊。

UPD: 這邊正的乘積需要先考慮\(K\)是奇數的情況並先添上一個正數,否則會被叉。

乘積為\(0\)的話墜簡單,輸出零就好了。

負數的乘積其實也很簡單,由於你已經通過先前的判斷證明了不能有正數或者零的乘積,那么只要貪心地取絕對值最小的那些正/負數乘起來就好了。

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

typedef long long ll;
const ll mod=1e9+7;

ll n,k,zero;
ll a[200005];
vector<ll> pos,neg;

void find_pos(){
    sort(pos.begin(),pos.end(),[](const ll &a,const ll &b){
        return a>b;
    });
    sort(neg.begin(),neg.end(),[](const ll &a,const ll &b){
        return a<b;
    });
    ll res=k&1?pos.front():1;
    ll pi=k&1,ni=0;
    while(pi+1<pos.size()&&ni+1<neg.size()&&pi+ni+2<=k){
        if(pos[pi]*pos[pi+1]>neg[ni]*neg[ni+1]){
            res=res*pos[pi]%mod*pos[pi+1]%mod;
            pi+=2;
        }else{
            res=res*neg[ni]%mod*neg[ni+1]%mod;
            ni+=2;
        }
    }
    while(pi+1<pos.size()&&pi+ni+2<=k){
        res=res*pos[pi]%mod*pos[pi+1]%mod;
        pi+=2;
    }
    while(ni+1<neg.size()&&pi+ni+2<=k){
        res=res*neg[ni]%mod*neg[ni+1]%mod;
        ni+=2;
    }
    cout<<(res+mod)%mod<<endl;
}

void find_neg(){
    sort(a,a+n,[](const ll &a,const ll &b){
        return abs(a)<abs(b);
    });
    ll res=1;
    for(ll i=0;i<k;i++){
        res=res*a[i]%mod;
    }
    cout<<(res+mod)%mod<<endl;
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>k;
    for(ll i=0;i<n;i++){
        cin>>a[i];
        if(a[i]>0)pos.emplace_back(a[i]);
        if(a[i]==0)zero++;
        if(a[i]<0)neg.emplace_back(a[i]);
    }
    if(neg.size()-(neg.size()&1)+pos.size()>=k&&(k&1)<=pos.size()){
        find_pos();
    }else if(zero){
        cout<<"0\n";
    }else find_neg();

    return 0;
}

F - Intervals on Tree

首先這是一棵樹,所以每一條邊都會合並左右結點從屬的兩個連通塊為一個。那么對於一條邊,對於所有包含它的\(S\)(定義同題目),它就會減少一個連通塊。

那么答案一開始就設成假如每個\(S\)中的點都是獨立的一個連通塊,一共有多少個連通塊,然后對於每一條邊,答案減去包含它的\(S\)的個數即可。

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

int n;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    long long ans=0;
    for(int i=1;i<=n;i++){
        ans+=(long long)(n-i+1)*i;
    }
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        if(a>b)swap(a,b);
        ans-=(long long)a*(n-b+1);
    }
    cout<<ans<<endl;

    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM