atcoder abc 359

A  count takahashi

问题:

思路:字符串比较

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    int ans = 0;
    for(int i = 1; i <= n; i ++ ) {
        string s;
        cin >> s;
        if(s[0] == 'T') ans ++;
    }
    cout << ans;
    return 0;
}

B couples

问题:

思路:找出所有a[i - 1]与a[i + 1]相等的pair

代码:
 

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(2 * n + 1);
    for(int i = 1; i <= 2 * n; i ++ ) cin >> a[i];
    int pre = a[1];
    int ans = 0;
    for(int i = 2; i <= 2 * n - 1; i ++ ) {
        if(a[i + 1] == pre) ans ++;
        pre = a[i];
    }
    cout << ans;
    return 0;
}

C tile distance2

问题:

思路:

注意到每次竖直方向上走一个可以在水平方向上多增加一个偏移量,因此只要先解决竖直方向,然后可以得到一个水平方向的最大范围,只要水平坐标在这个范围内就不用计算水平方向上的花费,反之计算差值除2即可。为了简化计算,可以把所有坐标在水平方向上偏移到砖块的左边部分。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    long long x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
    long long yy = abs(y1 - y2);
    long long t = min(x1, x2);
    x1 = max(x1, x2);
    x2 = t;
    if((y1 + x1) & 1) x1 --;
    if((y2 + x2) & 1) x2 --;
    //long long tmp = x1;
    x1 -= yy;
    if(x1 <= x2) cout << yy;
    else cout << yy + abs(x1 - x2) / 2;
    return 0;
}

D - Avoid K Palindrome

问题:

思路:
注意到k很小,话不多说,状态压缩。A为1,B为0

很显然只有一维的状态无法构造状态转移方程。再加一维索引dp[i][j]表示以下标i开头的字符串且状态为j的所有good string 的数量

则有dp[i][j] += dp[i - 1][k]

j与k之间又有什么联系呢,让他们错开一位上下摆放,就可以发现除了第一位和最后一位,其他位都是相同的。这时候让j减去最右边的数,并且整体右移一位!!!很重要,就因为这里,我调了一个小时代码。然后再加上str[i - 1]对应的数。

代码:

#include <bits/stdc++.h>

using namespace std;

const int mod = 998244353;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    cin >> n >> k;
    vector<char> str(n + 1);
    for(int i = 1; i <= n; i ++ ) cin >> str[i];

    vector<vector<int>> dp((n + 1), vector<int>(1 << k));
    for(int j = 0; j <= (1 << k) - 1; j ++ ) {
        bool flag = true;
        vector<char> s(k);
        for(int i = 0; i < k; i ++ ) {
            if(j >> i & 1) s[i] = 'A';
            else s[i] = 'B';
            if(str[i + 1] != '?' && str[i + 1] != s[i]) flag = false;
        }
        
        if(flag) {
            reverse(s.begin(), s.end());
            int num = 0;
            for(int i = 0; i < k; i ++ ) {
                if(s[i] == 'A') num += (1 << i) * 1;
            }
            if(num != j) dp[1][j] = 1;
        }
    }

    for(int i = 2; i <= n - k + 1; i ++ ) {
        for(int j = 0; j <= (1 << k) - 1; j ++ ) {
            bool flag = true;
            vector<char> s(k);
            for(int u = 0; u < k; u ++ ) {
                if(j >> u & 1) s[u] = 'A';
                else s[u] = 'B';
                if(str[i + u] != '?' && str[i + u] != s[u]) flag = false;
            }

            if(flag) {
                reverse(s.begin(), s.end());
                int num = 0;
                for(int u = 0; u < k; u ++ ) {
                    if(s[u] == 'A') num += 1 << u;
                }

                if(num != j) {
                    int tmp = j;
                    if(s[0] == 'A') tmp -= 1 << k - 1;
                    tmp <<= 1;
                    //if(j == 14) cout << tmp << " ";
                    if(str[i - 1] != 'A') (dp[i][j] += dp[i - 1][tmp]) %= mod;
                    if(str[i - 1] != 'B') {
                        tmp ++;
                        //if(j == 14 && i == 2) for(auto t: s) cout << t;
                        //if(dp[i - 1][tmp] && i == 2) cout <<j;
                        (dp[i][j] += dp[i - 1][tmp]) %= mod;
                    }
                }
            }
        }
    }

    int ans = 0;
    for(int i = 0; i <= (1 << k) - 1; i ++ ) (ans += dp[n - k + 1][i]) %= mod;
    cout << ans;
    return 0;
}

E water tank

问题:

思路:这题难度和CD不对等。

由图不难发现,这道题的答案实际上就是找到当前点i左边第一个高度大于等于它的点j,再用j的答案加上这块区域的面积。这就是单调栈的经典操作。答案就是ans[j] + (i - j) * h[i];

由于题目要求,输出时在答案后都加上1

代码:
 

#include <bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<long long> h(n + 1);
    vector<long long> ans(n + 1);

    h[0] = 1e9;
    for(int i = 1; i <= n; i ++ ) cin >> h[i];
    
    stack<long long> stk;
    stk.push(0);

    for(int i = 1; i <= n; i ++ ) {
        long long x = h[i];
        while(h[stk.top()] < x) stk.pop();
        int l = stk.top();
        ans[i] = ans[l] + (i - l) * h[i];
        stk.push(i);
    }

    for(int i = 1; i <= n; i ++ ) cout << ans[i] + 1 << " ";
    return 0;
}

F tree degree optimization

问题:

思路:

每个节点肯定会有一个度数,然后通过把不同的度数给不同的节点,会使得树的形态发生变化,从而导致答案发生变化。

可以用用一个小根堆存储点度数加1的贡献,则每次把度数加到堆顶,一定是最优解。

(j + 1)^2 * a[i]贡献为(2 * j + 1) * a[i];

代码:
 

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;

int main() {
    int n;
    cin >> n;
    vector<long long> a(n + 1);
    for(int i = 1; i <= n; i ++ ) cin >> a[i];

    long long ans = 0;
    priority_queue<PII, vector<PII>, greater<PII>> q;
    for(int i = 1; i <= n; i ++ ) {
        long long val = a[i] * (2 + 1);
        q.push({val, 1});
        ans += a[i];
    }

    n -= 2;
    while(n -- ) {
        auto t = q.top();
        q.pop();
        int j = t.second;
        long long x = t.first / (2 * j + 1);
        ans += t.first;
        j ++;
        long long val = x * (2 * j + 1);
        q.push({val , j});
    }
    cout << ans;
    return 0;
}

G

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值