2018 Benelux Algorithm Programming Contest (BAPC 18)

2018 Benelux Algorithm Programming Contest (BAPC 18)

B Birthday Boy
C Cardboard Container
G Game Night
J Janitor Troubles
K Kingpin Escape

B

题解:

A: 这题太恶心了, 记得是距离十月28号最近的。

B: 是的。

代码:

#include<bits/stdc++.h>
using namespace std;
int vis[400][400];

int day_diff(int year_start, int month_start, int day_start,int year_end , int month_end, int day_end){
    int y2, m2, d2;
    int y1, m1, d1;
     
    
    m1 = (month_start + 9) % 12;
    y1 = year_start - m1/10;
    d1 = 365*y1 + y1/4 - y1/100 + y1/400 + (m1*306 + 5)/10 + (day_start - 1);

    m2 = (month_end + 9) % 12;
    y2 = year_end - m2/10;
    d2 = 365*y2 + y2/4 - y2/100 + y2/400 + (m2*306 + 5)/10 + (day_end - 1);
    
    return d2 - d1;
}

struct node{
    int month, day;
};

vector<node>v;
vector<node>g[1000];

bool cmp(node x, node y){
    if(x.month == y.month){
        return x.day < y.day;
    }else{
        return x.month < y.month;
    }
}

int num[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

struct node change(struct node a){
    if(a.day == 1){
        
        a.month--;
        if(a.month == 0){
            a.month = 12;
        }
        a.day = num[a.month];
    }else{
        a.day--;
    }
    return a;
}


int main(){
    int n;
    
    scanf("%d", &n);
    string name, date;

    for(int i = 1; i <= n; i++){
        cin >> name >> date;
        int a = 0, b = 0;
        if(date[0] != '0') {
			a += date[0]-'0'; 
			a *= 10;
		}
		a += date[1]-'0';
		
		if(date[3] != '0') {
			b += date[3]-'0'; 
			b *= 10;
		}
		b += date[4]-'0';
        
        v.push_back({a, b});
        vis[a][b] = 1;

    }

    sort(v.begin(), v.end(), cmp);
  
    for(int i = 1; i < v.size(); i++){
        int cnt = day_diff(2018, v[i -1].month, v[i - 1].day, 2018, v[i].month, v[i].day);
        node cd = change(v[i]);
   
        
        if(vis[cd.month][cd.day])continue;
        
        g[cnt].push_back(cd);
    }
    int cnt = day_diff(2018, v[v.size() - 1].month, v[v.size() - 1].day, 2019, v[0].month, v[0].day);
    node cd = change(v[0]);
   
    if(vis[cd.month][cd.day] == 0){

        g[cnt].push_back(cd);
    }
    int f = 0;
    int ans =1000, mo = 0,da = 0;
    for(int i = 400; i; i--){
        if(g[i].size()){
     
            for(int j = 0; j < g[i].size(); j++){
                 int cnt = day_diff(2019, 10, 28, 2019, g[i][j].month, g[i][j].day);
                 
                 if(cnt < 0){
                     cnt = day_diff(2018, 10, 28, 2019, g[i][j].month, g[i][j].day);
                 }
                 if(ans > cnt){
                     ans = cnt;
                     da = g[i][j].day;
                     mo = g[i][j].month;
                     f = 1;
                 }
                
            } 
            if(f == 1)break;
           
        }
    }
    if(mo < 10){
        printf("0");
    }
    printf("%d-", mo);
    if(da <10){
        printf("0");
    }
    printf("%d\n", da);

}

C

题解:

A: 这题不就是枚举 \(a * b * c = v\) 找到 a, b, c三个整数 , 使得 \((a * b + a * c + b * c) * 2\) 的值最小。

B: 是的, 注意剪纸。

代码:

#include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll v;
     
    int main(){
        scanf("%lld", &v);
        int f = 0;
        for(int i = 2; i <= sqrt(v); i++){
            if(v % i == 0){
                f = 1;
                break;
            }
        }
        if(f == 0){
            ll ans = v * 4 + 2;
            printf("%lld\n", ans);
        }else{
            ll ans = LLONG_MAX;
            for(ll i = 1; i <= v; i++){
                if(v % i == 0){
                    ll cnt = v / i;
                    for(ll j = 1; j <= cnt; j++){
                        if(cnt % j == 0){
                            ll cnt1 = cnt / j;
                            
                            ll area = i * cnt1 + i * j + j * cnt1;
                            area = area * 2;
                     
                            ans = min(ans, area);
                        }
                    }
                }
            }
            printf("%lld\n", ans);
        }
    }

J

题解:

A: 这题你怎么写的?

B: 枚举角度。

A: 怎么枚举?

B: 因为误差控制在0.001所以角度总0.001(弧度制)枚举一直枚举到3.1415926

枚举一个角度可以用余玄定理算出边, 在通过表算出角度, 有了角度通过三角形求面积求出面积。

A: 哦哦, 我懂了。

B: 这题可以直接用公式求解, 但是证明有点复杂。

代码:

#include<bits/stdc++.h>
using namespace std;
 
double eps = 0.00000000001;
 
double a, b, c, d;
 
int main(){
    scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
    double ans = 0.0;
    double du = 0.0001;
    // a b
    int count = 0;
    while(du < 3.1415926){
    
        double x = a * a + b * b - 2 * a * b * cos(du);
        double o = d * d + c * c - x;
        o = o / (2 * d * c);
        o = acos(o);
        double area = a * b * sin(du) + d * c * sin(o);
        area = area / 2.0;
        ans = max(ans, area);
        
        du += 0.0001;
    }
    // a c
    du = 0.0001;
    while(du < 3.1415926){
    
        double x = a * a + c * c - 2 * a * c * cos(du);
        double o = d * d + b * b - x;
        o = o / (2 * b * d);
        o = acos(o);
        double area = a * c * sin(du) + b * d * sin(o);
        area = area / 2.0;
        ans = max(ans, area);
        
        du += 0.0001;
    }
 
    // a d
    du = 0.0001;
    while(du < 3.1415926){
    
        double x = a * a + d * d - 2 * a * d * cos(du);
        double o = c * c + b * b - x;
        o = o / (2 * b * c);
        o = acos(o);
        double area = a * d * sin(du) + b * c * sin(o);
        area = area / 2.0;
        ans = max(ans, area);
        
        du += 0.0001;
    }
 
    printf("%.6lf\n", ans);

G

题解:
A: 这题直接暴力枚举

代码:

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

const int N = 2e5 + 7;

int n, sum[N][3], a[N], b[N];
char s[N];

vector<pair<int, int> >v;

int main(){
    scanf("%d", &n);
    scanf(" %s", (s + 1));
    for(int i = 1; i <= n; i++){
        a[i] = s[i] - 'A';
    }

    int l = 1, r = n;
    int zero = 0, one = 0, two = 0;
    for(int i = 1; i <= n; i++){
        if(a[i] == 0){
            zero++;
        }else if(a[i] == 1){
            one++;
        }else if(a[i] == 2){
            two++;
        }
        sum[i][0] = zero;
        sum[i][1] = one;
        sum[i][2] = two;
    }
    v.push_back({zero, 0});
    v.push_back({one, 1});
    v.push_back({two, 2});
    v.push_back({0, 0});
    int ans = INT_MAX;
    int f = 1;
    for(int i = 1; i <= n; i++){
        int res = 0;
        int l = 0; 
        int r = 0;
        for(int j = 0; j < v.size(); j++){
     
            r += v[j].first;  
            if(v[j].second == 0){
                    res += v[j].first - (sum[r][0] - sum[l][0]);
            }else if(v[j].second == 1){
                    res += v[j].first - (sum[r][1] - sum[l][1]);
        
            }else if(v[j].second == 2){
                    res += v[j].first - (sum[r][2] - sum[l][2]);
    
                
            }
            l = r;
        }
        v[0].first--;
        v[3].first++;
        if(v[0].first == 0){
            v.erase(v.begin());
            v.push_back({0, f});
            f++;
        }
        ans = min(ans, res);
    }
    v.clear();
    v.push_back({zero, 0});  
    v.push_back({two, 2});
    v.push_back({one, 1});
    v.push_back({0, 0});
     f = 2;
    for(int i = 1; i <= n; i++){
        int res = 0;
        int l = 0; 
        int r = 0;
        for(int j = 0; j < v.size(); j++){
     
            r += v[j].first;   
            if(v[j].second == 0){
                    res += v[j].first - (sum[r][0] - sum[l][0]);
            }else if(v[j].second == 1){
                    res += v[j].first - (sum[r][1] - sum[l][1]);
        
            }else if(v[j].second == 2){
                    res += v[j].first - (sum[r][2] - sum[l][2]);
            }
            l = r;
        }
        v[0].first--;
        v[3].first++;
        if(v[0].first == 0){
            v.erase(v.begin());
            v.push_back({0, f});
            f--;
        }
        ans = min(ans, res);
    }

    printf("%d\n", ans);
}

k

题解:

A:这题咋想的?

B: 是将所有入度为1的点加入一个vector里面。

A: 为啥呢?

B: 你想呀入度为1, 是不是我把这个边堵了必输, 所有要把入度为1的点连在一起。

A:那怎么连才能使花费的边最少呢?

B:可以把这些点连成一个圈。

A: 我懂了。

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

const int N = 1e5 + 7;
int fa[N];
vector<int>g[N];
vector<int>ans;
vector<pair<int, int> >p;

int n, h;

void dfs(int u, int fa){
  
    if( g[u].size() == 1){
        ans.push_back(u);        
    }
    for(int to: g[u]){
        if(to == fa)continue;
        dfs(to, u);

    }
}

int main(){
    scanf("%d %d", &n, &h);
    h++;
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d %d", &u, &v);
        u++, v++;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    for(int i = 0; i < ans.size() / 2; i++){
        p.push_back({ans[i], ans[ans.size() / 2 + i]});
    }
    if(ans.size() % 2){
        p.push_back({ans[0], ans[ans.size() - 1]});
    }
    cout << p.size() << endl;
    for(auto it: p){
        cout << it.first - 1 << " " << it.second - 1 << endl;
    }
    
  
    
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值