Preliminaries for Benelux Algorithm Programming Contest 2019


A. Architecture

如果行最大值中的最大值和列最大值中的最大值不同的話,那么一定會產生矛盾,可以手模一個樣例看看。

當滿足行列最大值相同條件的時候,就可以判定了。

因為其余的地方一定可以構造出來符合條件的值,行列是很多的,填0就好了。

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

int main() 
{
    int n, m; cin >> n >> m;
    int t1, t2;
    t1 = t2 = 0;
    for(int i = 1, x; i <= n; i++)
    {
        scanf("%d", &x);
        t1 = max(t1, x);
    }
    for(int i = 1, x; i <= m; i++)
    {
        scanf("%d", &x);
        t2 = max(t2, x);
    }
    if(t1 == t2) puts("possible");
    else puts("impossible");
    return 0;
}

B. Bracket Sequence

用棧模擬即可,注意要取模

const int N = 300000 + 5;
const int mod = 1e9 + 7;
ll st[N], top, cnt;
int n;
char op[20];
ll get(char *s){
    int len = strlen(s);
    ll x = 0;
    for(int i=0;i<len;i++) x = x * 10 + s[i] - '0';
    return x;
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",op);
        if(op[0] == '(') {
            cnt ++;
            st[++top] = -1;
            continue;
        }
        else if(op[0] == ')'){
            if(st[top] == -1) {
                top --;
                continue;
            }
            ll x = st[top];
            while(top >= 2 && st[top-1] != -1){
                if(cnt % 2 == 0)x = (st[top-1] + x)%mod;
                else x = st[top-1] * x % mod;
                top--;
            }
            cnt --;
            top -= 2;
            st[++top] = x;
        }
        else{
            ll x = get(op);
            st[++top] = x;
        }
    }
    ll res = 0;
    while(top) res = (res + st[top--]) % mod;
    printf("%lld\n", res);
    return 0;
}

C. Canyon Crossing

二分一下最低高度,然后整個圖變成了 n*m 個點,邊權為0或1的圖,第一排為起點,最后一排為終點,跑最短路即可,由於邊權只有0和1,所以用雙端隊列維護即可

const int N = 1000 + 5;
#define mk make_pair
int n, m, k, a[N][N];
int d[N][N],c[N][N];
int dx[4] = {1,-1,0,0}, dy[4] = {0,0,1,-1};
pair<int,int> q[2000010];
bool check(int mid){
    memset(d, 0x3f, sizeof d);
    int l = 1000005,r = 1000004;
    for(int j=1;j<=m;j++)q[++r] = mk(0,j), d[0][j] = 0;
    while(l<=r){
        auto t = q[l++];
        int x = t.first, y = t.second;
        for(int i=0;i<4;i++){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 1 || nx > n || ny < 1 || ny > m)continue;
            if(a[nx][ny] >= mid){
                if(d[nx][ny] > d[x][y]){
                    d[nx][ny] = d[x][y];
                    q[--l] = mk(nx,ny);
                }
            }else{
                if(d[nx][ny] > d[x][y] + 1){
                    d[nx][ny] = d[x][y] + 1;
                    q[++r] = mk(nx,ny);
                }
            }
        }
    }
    for(int i=1;i<=m;i++)if(d[n][i] <= k) return true;
    return false;
}
int main() {
    scanf("%d%d%d",&n,&m,&k);
    int l = inf, r = 0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            l = min(l, a[i][j]);
            r = max(r, a[i][j]);
        }
    }
    while(l < r){
        int mid = l + r + 1 >> 1;
        if(check(mid))l = mid;
        else r = mid - 1;
    }
    printf("%d\n",l);
    return 0;
}

D. Deceptive Dice

\(ans\)\(i-1\) 輪的期望,設 \(t = \lfloor ans \rfloor\) ,那么第 \(i\) 輪的期望是

\[\frac{t}{n} * ans + \frac{\sum_{t+1}^{n}i}{n} \]

前面的表示有 \(t/n\) 的概率小於等於ans,那么第 i 次就不再擲色子。后面的就是取 [i+1, n] 的期望

const int N = 100 + 5;
int n, m;
double ans;
int get(int x){return x*(x+1) / 2;}
int main() {
    scanf("%d%d",&n,&m);
    ans = 1.0 * get(n) / n;
    for(int i=2;i<=m;i++){
        int t = ans;
        ans = 1.0 * t / n * ans + 1.0 * (get(n) - get(t)) / n;
    }
    printf("%.7f\n",ans);
    return 0;
} 

E. Exits in Excess

這個題有個關鍵的性質在於無自環。

設兩個集合\(S,T\)

考慮一條邊\(<x,y>\),如果\(x<y\),將這條邊插入\(S\);否則插入\(T\)

輸出邊集大小較小的集合。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> t1, t2;
int n, m;
int main() 
{
    cin >> n >> m;
    for(int i = 1, x, y; i <= m; i++)
    {
        scanf("%d%d", &x, &y);
        if(x < y) t1.push_back(i);
        else t2.push_back(i);
    }
    if(t1.size()>t2.size()) t1 = t2;
    cout << t1.size() << endl;
    for(auto x : t1)
        printf("%d\n", x);
    return 0;
}

F. Floor Plan

int n;
int main() {
    cin >> n;
    int flag = false;
    for(int i=2;i*i<=n;i++){
        if(n % i == 0){
            int res = n / i;
            if((res + i)%2 == 0){
                flag = true;
                int a = (res + i) / 2;
                int b = res - a;
                printf("%d %d\n",b, a);
                break;
            }
        }
    }
    if(!flag) puts("impossible");
    return 0;
}

G. Greetings!

const int N = 100000 + 5;
char s[N];
int main() {
    cin >> s;
    int n = strlen(s);
    printf("h");
    for(int i=0;i<2*(n-2);i++)printf("e");
    printf("y");
    return 0;
}

H. Hexagonal Rooks

從起點走兩步走到終點,枚舉中間的那個點,判斷它與起點和終點是否可以一步達到即可,判斷細節比較重要,把大於縱坐標大於 'f' 的對稱往上翻即可,用幾種case找找規律即可。

char x, x2;
int y, y2;
bool check(int x, int y, int x2, int y2){
    if(x == x2 && y == y2) return false;
    if(x == x2) return true;
    if(x > 6) y += x - 6;
    if(x2 > 6) y2 += x2 - 6;
    if(y == y2 || y - x == y2 - x2) return true;
    return false;   
}
int main() {
    cin >> x >> y >> x2 >> y2;
    int res = 0;
    for(int i=1;i<=11;i++){
        int cnt = 11 - abs(6 - i);
        for(int j=1;j<=cnt;j++){
            if(check(i, j, x-'a'+1, y) && check(i, j, x2-'a'+1, y2)) res++;
        }
    }
    cout << res << endl;
    return 0;
}

I. Inquiry I

const int N = 1000000 + 5;
ll a[N], b[N], sa[N], sb[N];
int n;

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i] = a[i]*a[i];
    ll res = 0;
    for(int i=1;i<=n;i++) sa[i] = sa[i-1] + a[i], sb[i] = sb[i-1] + b[i];
    for(int i=0;i<=n;i++){
        res = max(res, sb[i] * (sa[n] - sa[i]));
    }
    printf("%lld\n",res);
    return 0;
}

K. Knapsack Packing

首先排個序,最小的一定是0(空集產生的和),然后次小的就是集合中最小的數了。之后每次找到一個新的數字(即最終答案集合中的數字),都用它與之前所有組合出來的數字進行求和,將這些新的數字填入到一個集合中,再接下來的掃描過程中,如果發現有該集合的數字,則一定不是答案集合中的數字,將其從集合中刪除即可。

const int N = 300000 + 5;
int n, m, a[N];
multiset<int> st, tmp;
map<int,int> mp;
vector<int> res;
int main() {
    scanf("%d",&n);
    m = 1 << n;
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    sort(a+1,a+1+m);
    if(a[1] != 0){
        puts("impossible");
        return 0;
    }
    int cnt = 0;
    for(int i=2;i<=m;i++){
        if(mp[a[i]]){
            mp[a[i]] --;
            continue;
        }else{
            cnt ++;
            res.push_back(a[i]);
            for(auto x:st){
                tmp.insert(x + a[i]);
            }
            for(auto x : tmp) {
                st.insert(x);
                mp[x] ++;
            }
            st.insert(a[i]);
            tmp.clear();
        }
        if(cnt > n){
            puts("impossible");
            return 0;
        }
    }
    sort(res.begin(),res.end());
    for(auto x : res)printf("%d\n",x);
    return 0;
}

L. Lifeguards

將點按照坐標軸排序,找到中間的點,對於n的奇偶進行分別處理。

n 為奇數則構造一個幾乎平行於y軸且通過中間點的直線,可以想到做這條直線的垂直平分線可以將所有點分成兩半

n 為偶數則構造一個幾乎平行於y軸且不通過中間點的直線,這樣的直線的垂直平分線也同樣會把所有點分成兩半

const int N = 100000 + 5;
pair<ll,ll> a[N];
int n;
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].first, &a[i].second);
    sort(a + 1, a + 1 + n);
    int mid = (n + 1) / 2;
    ll Len = 1000000000000ll;
    ll x = a[mid].first, y = a[mid].second;
    if(n & 1){
        printf("%lld %lld\n", x - Len, y-1);
        printf("%lld %lld\n", x + Len, y+1);
    }else{
        printf("%lld %lld\n", x - Len, y);
        printf("%lld %lld\n", x + Len, y+1);
    }
    return 0;
}


免責聲明!

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



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