1. 程式人生 > 實用技巧 >訓練賽

訓練賽

CCSU團隊訓練賽

H - Billionaires URAL - 1650

​ You probably are aware that Moscow holds the first place in the world with respect to the number of billionaires living there. However, the work of billionaires is such that they have to travel a lot. That is why some other city can be the first in such a list on certain days. Your friends from FSB, FBI, MI5, and Shin Bet have provided you with information about movements of billionaires during some period of time. Your employer asks you to determine for each city the number of days during this period on which this city exceeded all other cities in the total amount of money that billionaires staying in this city have.

Input

​ In the first line you are given the number n of billionaires (1 ≤ n ≤ 10000) . The following n lines contain information about these people: their names, cities where they were staying at the beginning of the period, and their fortunes. In the next line you are given the number m

of days in the period for which you have the information (1 ≤ m ≤ 50000) and the number k of travels of the billionaires (0 ≤ k ≤ 50000) . The following k lines contain the list of travels in the following format: the number of the day (from 1 to m−1
), the name of the person, and the city of destination. You may assume that billionaires depart late at night and arrive to the destination city on the next day's morning. They cannot make more than one travel each day. The numbers of days in the list are not decreasing. All names of people and cities consist of at most 20 English letters; you must take into consideration the case of the symbols. The fortunes are in the range from 1 to 100 billions (one billion is a thousand million).

Output

​ In each line of the output give the name of a city and, after a space, the number of days during which this city was the first with respect to the sum of fortunes of the billionaires staying there. Leave out those cities for which there were no such days. The cities must be sorted alphabetically (with the usual symbol order: ABC...Zabc...z).

Example

input output
5 Abramovich London 15000000000 Deripaska Moscow 10000000000 Potanin Moscow 5000000000 Berezovsky London 2500000000 Khodorkovsky Chita 1000000000 25 9 1 Abramovich Anadyr 5 Potanin Courchevel 10 Abramovich Moscow 11 Abramovich London 11 Deripaska StPetersburg 15 Potanin Norilsk 20 Berezovsky Tbilisi 21 Potanin StPetersburg 22 Berezovsky London Anadyr 5 London 14 Moscow 1

題解:噁心的題線段樹模擬記住是先算貢獻再更新

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

typedef long long ll;

const int N = 1e5 + 7;
struct segement{
    ll maxn, maxn1;
    int pos;
}tree[4 * N];
ll a[N];

#define lson 2 * node
#define rson 2 * node + 1
#define m (l + r) / 2

struct data{
    string na, ad;

};

void build(int l, int r, int node){
    if(l ==  r){
        tree[node].maxn = a[l];
        tree[node].maxn1 = 0;
        tree[node].pos = l;
        return;
    }
    build(l, m, lson);
    build(m + 1, r, rson);
    if(tree[rson].maxn > tree[lson].maxn){
        tree[node].maxn = tree[rson].maxn;
        tree[node].pos = tree[rson].pos;
        if(tree[rson].maxn1 > tree[lson].maxn){
            tree[node].maxn1 = tree[rson].maxn1;

        }else{
            tree[node].maxn1 = tree[lson].maxn;
        }
    }else{
        tree[node].maxn = tree[lson].maxn;
        tree[node].pos = tree[lson].pos;
        if(tree[lson].maxn1 > tree[rson].maxn){
            tree[node].maxn1 = tree[lson].maxn1;
        }else{
            tree[node].maxn1 = tree[rson].maxn;
        }
    }
}

void update(ll v, int pos, int l, int r, int node){
    if(l == r){
        tree[node].maxn += v;
        return;
    }
    if(pos <= m) update(v, pos, l, m, lson);
    else update(v, pos, m + 1, r, rson);
    if(tree[rson].maxn > tree[lson].maxn){
        tree[node].pos = tree[rson].pos;
        tree[node].maxn = tree[rson].maxn;
        if(tree[rson].maxn1 > tree[lson].maxn){
            tree[node].maxn1 = tree[rson].maxn1;
        }else{
            tree[node].maxn1 = tree[lson].maxn;
        }
    }else{
        tree[node].maxn = tree[lson].maxn;
        tree[node].pos = tree[lson].pos;
        if(tree[lson].maxn1 > tree[rson].maxn){
            tree[node].maxn1 = tree[lson].maxn1;
        }else{
            tree[node].maxn1 = tree[rson].maxn;
        }
    }
}


vector<data> g[N];

map<string , string> name;
map<string, int> address;
map<string, ll>money;
map<string, int>ans;
string cnt[N];

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, day, q;
    cin >> n;
    int top = 1;
    for(int i = 1; i <= n; i++){
        string na, ad;
        ll w;
        cin >> na >> ad >> w;
        money[na] = w;
        name[na] = ad;
        if(address[ad]){
            a[address[ad]] += w;
        }else{
            a[top] = w;
            cnt[top] = ad;
            address[ad] = top++;
        }
    }
    int maxn  = 100000;
    build(1, maxn, 1);
    cin >> day >>q;
    while(q--){
        int d;
        string ad, na;
        cin >> d>> na>> ad;
        g[d].push_back({na, ad});
    }

    for(int i = 1; i <= day; i++){
        if(tree[1].maxn1 != tree[1].maxn){
            ans[cnt[tree[1].pos]]++;
        }
        for(int j = 0; j < g[i].size(); j++){
            string na = g[i][j].na;
            string ad = g[i][j].ad;
            string last_ad = name[na];
            name[na] = ad;
            int pos = address[last_ad];
            ll va = money[na];
            update(-va, pos, 1, maxn, 1);
            if(address[ad] == 0){
                cnt[top] = ad;
                address[ad] = top++;
            }
            pos = address[ad];
             va = money[na];

            update(va, pos, 1, maxn, 1);
        }

        
       

    }

    for(auto it: ans){
        cout <<it.first <<" " << it.second << endl;
    }

}

/*
5
Abramovich London 10000000000
Deripaska Moscow 10000000000
Potanin Moscow 5000000000
Berezovsky London 2500000000
Khodorkovsky Chita 1000000000
25 9
1 Abramovich Anadyr
5 Potanin Courchevel
10 Abramovich Moscow
11 Abramovich London
11 Deripaska StPetersburg
15 Potanin Norilsk
20 Berezovsky Tbilisi
21 Potanin StPetersburg
22 Berezovsky London
*/

G - Sum of Digits URAL - 1658

題意: 給你s1, s2分別表示 一個數每個數字之和等於s1 每個數字之間數字的平方和等於s2

求一個最小的這樣的數字。如果沒用輸出 No solution 如果這個數字的長度大於100輸出

No solution

題解:

\(dp[i][j]\) 表示每個數字之和為i, 每個數字平方和為j能得到的最小長度。

初始化時 把\(dp\)陣列賦值為無窮大,\(dp[0][0] = 0\)

那麼\(dp[i][j]\) = \(min(dp[i][j], dp[i - k][i - k *k ])\) 其中k為 1到9

知道每種狀態最優的最小長度,怎麼才能求出答案呢?

我們可以貪心。

\(if(dp[s1 - k][s2 - k * k] + 1 == dp[s1][s2])\) 其中k 是從1 到 9 開始貪心

如果這個條件成立, 那麼 第1位數就可以選 k, 然後 s1 = s1 - k, s2 = s2 - k *k

一直貪最小的最後得到一個最優解

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

int dp[1000][10000];

int s1, s2;

int main(){

    for(int i = 0; i < 1000; i++){
        for(int j = 0; j < 10000; j++){
            dp[i][j] = 1000;
        }
    }
    dp[0][0] = 0;
    for(int i = 1; i <= 9; i++){
        for(int j = 1; j < 1000; j++){
            for(int k = 1; k < 10000; k++){
                if(j - i >= 0 && k - i * i >= 0)
                    dp[j][k] = min(dp[j][k], dp[j - i][k - i * i] + 1);
            }
        }
    }
    int t; scanf("%d", &t);
    while(t--){
        scanf("%d %d", &s1, &s2);

        if(s1 >= 1000 || s2 >= 10000){
            printf("No solution\n");
        }else if(dp[s1][s2] > 100){
            printf("No solution\n");
        }else{
            vector<int>v;
            int ans = dp[s1][s2];
            while(1){
                for(int i = 1; i <= 9; i++){
                    if(dp[s1 - i][s2 - i * i] + 1 == dp[s1][s2]){
                        v.push_back(i);
                        s1 = s1 - i;
                        s2 = s2 - i * i;
                        break;
                    }
                }
                if(v.size() == ans){
                    break;
                }
            }
            for(int i: v){
                printf("%d", i);
            }
            puts("");
        }
    }    
    
}

Shortest Subchain URAL - 1651

題意:給你一個串數字, 表示從第一位置 到最後一個位置走的路徑, 問找一個從第一個位置到最後一個位置的最短路徑, 且走的邊的順序和給的順序一樣(也就是 後走的邊一定不能再先走的邊前面)。

題解:

這題看起來好難寫, 但是會了建圖這題就簡單了。

要是沒用後面的條件很多直接建圖跑個BFS就可以了。但是有了這個條件就無從下手。

我們可以, 按照位置建圖, 也就是第一個點的位置與第二個點的位置(i --> i + 1)建立一條有向邊且邊權為1, 這樣可以保證走的路徑一定是按照題目的意思。

然後我再找 a[i]再i位置前面離i最近的點建一天權值為0的有向邊, 圖建好了, 就是簡單的迪傑斯特拉了。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int a[N], n, pos[N];

struct node{
    int u, v;
    bool operator <(const node a)const{
        return v > a.v;
    }
};

vector<pair<int, int> >g[N];
priority_queue<node>q;
int dist[N], vis[N], fa[N];

void dij(){
    q.push({1, 0});
    for(int i = 1; i <= n; i++){
        vis[i] = 0;
        dist[i] = 1e8;
        fa[i] = 0;
    }
    dist[1] = 0;

    while(q.size()){
        node cd = q.top();
        q.pop();
        if(vis[cd.u])continue;
        for(auto it: g[cd.u]){
            int to = it.first;
            int cost = it.second;
            if(dist[to] > dist[cd.u] + cost){
                dist[to] = dist[cd.u] + cost;
                q.push({to, dist[to]});
                fa[to] = cd.u;
            }
        }
    }
}
vector<int>v;

int main(){
    while(~scanf("%d", &n)){
        v.clear();

        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            g[i].clear();
            pos[a[i]] = 0;
        }
        for(int i = 1; i < n; i++){
            g[i].push_back({i + 1, 1});
        }
        for(int i = 1; i <= n; i++){
            if(pos[a[i]]){
                g[pos[a[i]]].push_back({i, 0});
            }
            pos[a[i]] = i;
        }
        dij();
        int x = n;

        while(x){
            v.push_back(a[x]);
            x = fa[x];
        }
        v.push_back(-1);
        reverse(v.begin(), v.end());
        for(int i = 1; i < v.size(); i++){
            if(v[i] == v[i - 1])continue;
            printf("%d ", v[i]);
        }
        puts("");

    }
}