AtCoder Beginner Contest 160


比賽鏈接:https://atcoder.jp/contests/abc160/tasks

AtCoder Beginner Contest 160

A - Coffee

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;cin>>s;
    cout<<(s[2]==s[3]&&s[4]==s[5]?"Yes":"No");
    return 0;
}
View Code

B - Golden Coins

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int x;cin>>x;
    cout<<(x/500*1000+x%500/5*5);
    return 0;
}
View Code

C - Traveling Salesman around Lake

題意:環形池塘的一周坐落着幾戶人家,問以一戶為起點拜訪完所有人家的最短路程 。

思路:對於最短路程來說,無論是順時針還是逆時針都不會改變,所以按照題目給出的順時針順序兩兩相減即可,差小於零代表着逆時針需要走的路程,加上一個圓周即是順時針需要走的路程。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int k,n;cin>>k>>n;
    int a[n];for(int &i:a) cin>>i;
    int mi=numeric_limits<int>::max();
    for(int i=0;i<n;i++) mi=(mi,a[(i+n-1)%n]-a[i]+k)%k;
    cout<<mi;
    return 0;
}
View Code

D - Line++

題意:一條鏈中再有不相鄰兩點相連,問最短距離為1~N-1的點對各有多少。

思路:BFS得到每個點到其他點的最短距離。

#include <bits/stdc++.h>
using namespace std;
const int M=2200;
vector<int> e[M];
int dis[M][M],ans[M];
void bfs(int st){
    queue<int> q;
    dis[st][st]=1;
    q.push(st);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int v:e[u])
            if(dis[v][st]==0){
                dis[v][st]=dis[u][st]+1;
                q.push(v);
            }
    }
}
int main(){
    int n,x,y;cin>>n>>x>>y;
    for(int i=0;i<n-1;i++){
        e[i].push_back(i+1);
        e[i+1].push_back(i);
    }
    --x,--y;
    e[x].push_back(y);
    e[y].push_back(x);
    for(int i=0;i<n;i++)
        bfs(i);
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
            ++ans[dis[i][j]-1];
    for(int i=1;i<n;i++)
        cout<<ans[i]<<"\n";
    return 0;
}
View Code

E - Red and Green Apples

題意:有A個紅蘋果,B個綠蘋果,C個無色蘋果(可以當作紅蘋果或綠蘋果),每個蘋果有一個可口度,若要吃掉X個紅蘋果,Y個綠蘋果(X≤A,Y≤B),問最大可口度之和。

思路:取A中X個較可口的紅蘋果,B中Y個較可口的綠蘋果,如C中有更可口的無色蘋果替換之。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x,y,a,b,c;cin>>x>>y>>a>>b>>c;
    vector<int> v1(a),v2(b),v3(c);
    for(int &i:v1) cin>>i; 
    for(int &i:v2) cin>>i; 
    for(int &i:v3) cin>>i;
    sort(v1.rbegin(),v1.rend());
    sort(v2.rbegin(),v2.rend());
    for(int i=0;i<x;i++) v3.push_back(v1[i]);
    for(int i=0;i<y;i++) v3.push_back(v2[i]);
    sort(v3.rbegin(),v3.rend());
    cout<<accumulate(v3.begin(),v3.begin()+x+y,0LL);
    return 0;
}
View Code

F - Distributing Integers

參考了 BakaCirno 、tttttttttrx 兩位大大的博客。

題意:給一棵 $n$ 點樹染色,每次只能選擇與已染色結點相鄰的未染色結點,所用顏色依次為 $1 \sim n$,問以每個結點為起點時的染色情況總數。

思路:$n$ 個點染色的全排列情況為 $n!$,對於一棵樹中的每棵子樹,它的根一定要在這棵子樹的排列的第一個,即該棵子樹的排列中只有 $\frac{1}{size}$ 個是合法的,那么所有排列中就只有 $\frac{1}{\prod_{u=1}^{n}{size[u]}}$ 種是合法的,答案即 $\frac{n!}{\prod_{u=1}^{n}{size[u]}}$ 。

之后考慮如何換根,假設已經得到以 $fa$ 為根的答案,考慮結點 $fa$ 和它的一個子結點 $son$:

$ans[fa] = \frac{n!}{n\ *\ size[son]\ *\ size[x]}$,$n$ 即 $size[fa]$,$size[x]$ 是除父子結點外所有子樹的合法情況。

因為以二者為根的兩棵樹中,相差的只有以另一方為子樹根的 $size$ 數,其他的子樹結點都是相同的,如果根為 $fa$,以 $son$ 為子樹根的子樹大小為 $size[son]$,那么根為 $son$,以 $fa$ 為子樹根的子樹大小即為 $n\ -\ size[son]$,由此可以求得:

$ans[son] = \frac{n!}{n\ *\ size[n\ -\ size[son]]\ *\ size[x]}$

據此,我們先算出一個點的答案,然后在從該點出發遍歷樹的過程中遞推出所有子結點的答案。

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

const int M = 2e5 + 100;
const int mod = 1e9 + 7;

vector<int> e[M];
int n, sz[M], ans[M];
int fac[M], inv[M];

LL mul(LL a, LL b) {
    return a * b % mod;
}

void init() {
    fac[0] = 1;
    for (int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i);
    inv[1] = 1;
    for (int i = 2; i <= n; i++) inv[i] = mul((mod - mod / i), inv[mod % i]);
}

void dfs(int u, int fa) {
    sz[u] = 1;
    for (int v : e[u]) {
        if (v != fa) {
            dfs(v, u);
            sz[u] += sz[v];
        }
    }
}

void reroot(int u, int fa) {
    ans[u] = mul(mul(ans[fa], sz[u]), inv[n - sz[u]]);
    for (int v : e[u]) {
        if (v != fa) {
            reroot(v, u);
        }
    }
}

int main() {
    cin >> n;
    init();
    for (int i = 0; i < n - 1; i++) {
        int u, v; cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1, 0);
    ans[1] = fac[n];
    for (int i = 1; i <= n; i++) ans[1] = mul(ans[1], inv[sz[i]]);
    for (int v : e[1]) reroot(v, 1);
    for (int i = 1; i <= n; i++) cout << ans[i] << "\n";
}
View Code

 


免責聲明!

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



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