atcoder ABC 374

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

int main() {
    string s;
    cin >> s;
    reverse(s.begin(), s.end());
    if(s[0] == 'n' && s[1] == 'a' && s[2] == 's') cout << "Yes";
    else cout << "No";
    return 0;
}

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

int main() {
    string a, b;
    cin >> a >> b;
    if(a == b) cout << 0;
    else {
        for(int i = 1; i <= max(a.length(), b.length()); i ++ ) {
            if(a[i - 1] != b[i - 1]) {
                cout << i;
                break;
            }
        }
    }
    return 0;
}

C separated lunch

问题:

思路:注意到n很小,考虑爆搜

代码:

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

int main() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    int sum = 0;
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        sum += a[i];
    }
    int ans = 0x3f3f3f3f;
    function<void(int, int)> dfs = [&](int start, int cnt) {
        if(cnt >= sum - cnt) {
            ans = min(ans, cnt);
            return;
        }

        for(int i = start; i <= n; i ++ ) {
            dfs(i + 1, a[i] + cnt);
        }
    };

    dfs(1, 0);
    cout << ans;
    return 0;
}

D laser marking

问题:

思路:注意到n很小,因此考虑爆搜,对于所有的点,枚举出所有的连接顺序,这一点可以用next_permutation很快的实现(注意next permutation枚举的是字典序不大于当前序列的所有排列,因此想要枚举所有的情况,应在最开始对原有序列进行sort操作使得原有序列的字典序最小)

枚举出所有序列后再跑dfs枚举出这种序列下对于所有的线段哪一个端点优先连接

代码:
 

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

const double eps = 1e-8;

double find(double x) {
    double l = 0, r = 10000000000;
    while(l + eps <= r) {
        double mid = (l + r) / 2;
        if(mid * mid >= x) r = mid;
        else l = mid;
    }
    return l;
}

int main() {
    double n, s, t;
    scanf("%lf%lf%lf", &n, &s, &t);    
    vector<pair<pair<double, double>, pair<double, double>>> pos(n + 1);
    for(int i = 1; i <= n; i ++ ) {
        double x, y;
        double x1, y1;
        scanf("%lf%lf%lf%lf", &x, &y, &x1, &y1);
        pos[i] = {{x, y}, {x1, y1}};
    }
    sort(pos.begin() + 1, pos.end());
    double ans = 1e9;
    do {
        //for(int i = 1; i <= n; i ++ ) 
        double cnt = 1e9;
        function<void(double, double, pair<double, double>)> dfs = [&](double u, double now, pair<double, double> last) {
            if(u == n + 1) {
                //cout << now << endl;
                cnt = min(now, cnt);
                return;
            }

            /*double b = find(((pos[u].first.first - last.first) * (pos[u].first.first - last.first) + (pos[u].second.second - last.second) * (pos[u].second.second - last.second))) / s;
            
            b += find(((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second))) / t;

            dfs(u + 1, now + b, {pos[u].second.first, pos[u].second.second});

            b = find((pos[u].second.first - last.first) * (pos[u].second.first - last.first) + (pos[u].first.second - last.second) * (pos[u].first.second - last.second)) / s;
            
            b += find(((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second))) / t;

            dfs(u + 1, now + b, {pos[u].first.first, pos[u].first.second});*/
            double b = find((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second)) / t;
        
            double c = find((pos[u].first.first - last.first) * (pos[u].first.first - last.first) + (pos[u].first.second - last.second) * (pos[u].first.second - last.second)) / s;
            c += b;
            dfs(u + 1, now + c, {pos[u].second.first, pos[u].second.second});
            c = find((pos[u].second.first - last.first) * (pos[u].second.first - last.first) + (pos[u].second.second - last.second) * (pos[u].second.second - last.second)) / s;
            c += b;
            dfs(u + 1, now + c, {pos[u].first.first, pos[u].first.second});
        };

        dfs(1, 0, {0, 0});
        ans = min(ans, cnt);
    } while(next_permutation(pos.begin() + 1, pos.end()));
    printf("%.6lf", ans);
    return 0;
}

问题:

思路:求最小的最大值,显然二分,二分出答案之后,对于每个i,贪心地使得处理的机器大于二分的值,并且花费最小。对于每个i都有两种不同的选择,每个选择处理的数量 / 每个选择的价格 这个比值越大,就说明这种选择性价比越高,同时要注意到,选择性价比最好的机器不一定是最佳方案,因为可以有冗余,例如一个机器性价比很高,但价钱很贵,并且处理数量远远高出了我们的需求。这时注意到每种机器处理的数量都是不大于100的,这也就意味着性价比较差的那一台机器最多不会超过100台。例如高性价比机器a与其他机器b a可处理100个机器,b可处理1个机器,当有100台b时,是不如一台a更优的,因此可以枚举机器b的数量,时间复杂度o(100 * 100 * logV)

代码:

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

typedef long long ll;

int main() {
    ll n, x;
    cin >> n >> x;
    vector<pair<ll, ll>> a(n + 1), b(n + 1);
    for(ll i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second >> b[i].first >> b[i].second;//first数量second价格

    auto check = [&](ll mid) {
        ll now = 0;
        for(ll i = 1; i <= n; i ++ ) {
            ll num = a[i].first, cost = a[i].second;
            ll num1 = b[i].first, cost1 = b[i].second;
            if((double)b[i].first / b[i].second > (double)a[i].first / a[i].second) {
                num = b[i].first;
                cost = b[i].second;
                num1 = a[i].first;
                cost1 = a[i].second;
            }//num cost是性价比高的机器

            ll cnt = (mid + num - 1) / num * cost;
            for(ll j = 0; j <= min(100ll, (mid + num1 - 1) / num1); j ++ ) {//枚举性价比低的机器要多少台
                cnt = min(cnt, j * cost1 + (mid - (j * num1) + num - 1) / num * cost);
            }
            now += cnt;
        }
        return now <= x;
    };

    ll l = 0, r = 1000000000;
    while(l < r) {
        ll mid = l + r + 1 >> 1;
        if(check(mid)) l = mid; 
        else r = mid - 1;
    }
    cout << l;
    return 0;
}

F Shipping

问题:

思路:注意到n很小,时间t很大。如果不考虑时间的数据范围,这就是一道简单dp。设状态dp[i][j]表示从前i个时间段内选择,并且当前已经运送了j个物品第i个时间段我们可以由两个状态转移过来,即从i - x与i - 1转移,从i - 1转移表示第i个操作不用送任何物品,那么i - 1满足的状态i一定满足,因为不运送物品的天数增加了,对答案更加有利从i - x的转移就表示在这一天我要运输货物,那么从dp[i - x][j]就可以转移到dp[i][j ~ j + k]当然,如果dp[i - x][j]的数据非法的话,就直接跳过。这也是一种状态机dp。仔细观察后发现,如果我们贪心的去运输货物,那么运输货物的时间一定位于ti + z * x其中z是非负整数,并且题目中x,k均小于100,也就是说所有可能运输货物的时间不超过100 * 100个这样就实现了对时间离散化的处理

该题的时间复杂度为O(n ^ 3 * k) 数据范围100可以过

代码:

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

typedef long long ll;
const ll INF = 1e18;

int main() {
    ll n, k, x;
    cin >> n >> k >> x;
    vector<ll> ti;
    vector<ll> t(n + 1);
    ti.push_back(-1e18);
    for(int i = 1; i <= n; i ++ ) {
        cin >> t[i];
        for(int j = 0; j <= 100; j ++ ) {
            ti.push_back(t[i] + j * x);
        }
    }

    sort(ti.begin(), ti.end());
    ti.erase(unique(ti.begin(), ti.end()), ti.end());

    auto find = [&](ll x) {
        int l = 0, r = ti.size() - 1;
        while(l < r) {
            int mid = l + r + 1 >> 1;
            if(ti[mid] <= x) l = mid;
            else r = mid - 1;
        }
        return l;
    };
    /*
        dp[i][j]  p[pre][]
    */
    vector<vector<ll>> dp((n * 101 + 1), vector<ll>((n + 1), INF));
    dp[0][0] = 0;
    ll len = ti.size();
    //cout << len;
    for(int i = 1; i <= len - 1; i ++ ) {
        ll pre = find(max(0ll, ti[i] - x));
        //if(i == 1) cout << pre << " ";
        //cout << pre << " ";
        for(int j = 0; j <= n; j ++ ) {
            dp[i][j] = min(dp[i][j], dp[i - 1][j]);
            if(dp[pre][j] == INF) continue;
            dp[i][j] = min(dp[i][j], dp[pre][j]);
            ll cnt = 0;
            for(int u = j + 1; u <= min(n, j + k); u ++ ) {
                if(t[u] > ti[i]) break;
                cnt += t[u];
                dp[i][u] = min(dp[i][u], dp[pre][j] + ti[i] * (u - j) - cnt); 
            }
        }
    }

    ll ans = INF;
    for(int i = 1; i <= len - 1; i ++ ) ans = min(ans, dp[i][n]);
    cout << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值