AtCoder Regular Contest 170 A-C

A - Yet Another AB Problem

贪心

定义下标i满足S[i]=B,T[i]=ABA型,S[i]=B,T[i]=AAB型,AA型、BB型同理。

对所有BA型的下标i去匹配其右侧的第一个AB型的下标j,匹配成功则对下标ij进行操作,若无法匹配,则对剩余的BA型下标i去匹配其右侧的BB型下标j和对剩余的AB型下标i去匹配其左侧的AA型下标j,匹配成功则对下标ij进行操作,若无法匹配则输出1,能完成匹配则输出操作数。

时间复杂度:O(nlogn),用vector替代set可优化至O(n)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

int main()
{
    cctie;
    
    int n; cin >> n;
    string S, T; cin >> S >> T;
    set<int> atob, btoa;
    for (int i = 0; i < n; i++) 
    {
        if (S[i] == T[i]) continue;
        if (S[i] == 'B' && T[i] == 'A') btoa.insert(i);
        else atob.insert(i);
    }
    int ans = 0;
    while (!btoa.empty() && !atob.empty() && *btoa.begin() < *(--atob.end()))
    {
        int k = *btoa.begin();
        auto ita = atob.upper_bound(k);
        int t = *ita;
        S[k] = 'A', S[t] = 'B';
        btoa.erase(k);
        atob.erase(t);
        ans++;
    }
    if (!atob.empty())
    {
        int k = n;
        for (int i = 0; i < n; i++)
        {
            if (S[i] == T[i] && S[i] == 'A')
            {
                k = i;
                break;
            }
        }
        if (k < *atob.begin()) ans += atob.size();
        else ans = -1;
    }

    if (ans != -1 && !btoa.empty())
    {
        int k = -1;
        for (int i = n - 1; i >= 0; i--)
        {
            if (S[i] == T[i] && S[i] == 'B')
            {
                k = i;
                break;
            }
        }
        if (k > *(--btoa.end())) ans += btoa.size();
        else ans = -1;
    }

    cout << ans << '\n';
    
    return 0;
}

B - Arithmetic Progression Subsequence

枚举、二分

记符合题目要求的区间为符合区间。

[l,r]为符合区间时,所有区间[x,y],1xl,ryn必然也是符合区间,考虑对每一个下标i,1in求出所有以i为左端点的符合区间的最小右端点r,则以i为左端点的非符合区间数为r[i]i。由于数组中每个数[1,10],可以枚举所有三元组i,j,p,满足相邻两数差值相等即ji=pj=k,然后用二分更新所有对应值为i的下标的最小右端点r。答案即为(n+1)n2i=1n(r[i]i)

时间复杂度:O(nlogn)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long 
#define all(x) x.begin(), x.end()

int main()
{
    cctie;
    
    int n; cin >> n;
    vector<int> b(n + 1);
    vector a(11, vector<int>(0));
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
        a[b[i]].push_back(i);
    }
    vector<int> r(n + 2, n + 1);
    for (int k = 1; k <= 4; k++)
    {
        for (int i = 1; i + 2 * k <= 10; i++)
        {
            int j = i + k;
            int p = j + k;
            for (auto ii : a[i])
            {
                auto jj = upper_bound(all(a[j]), ii);
                if (jj == a[j].end()) break;
                auto pp = upper_bound(all(a[p]), *jj);
                if (pp == a[p].end()) break;
                r[ii] = min(r[ii], *pp);
            }
            for (auto pp : a[p])
            {
                auto jj = upper_bound(all(a[j]), pp);
                if (jj == a[j].end()) break;
                auto ii = upper_bound(all(a[i]), *jj);
                if (ii == a[i].end()) break;
                r[pp] = min(r[pp], *ii);
            }
        }
    }
    for (int i = 1; i <= 10; i++)
        for (int j = 2; j < a[i].size(); j++)
            r[a[i][j - 2]] = min(r[a[i][j - 2]], a[i][j]);
    i64 ans = 1LL * (1 + n) * n / 2;
    for (int i = n; i >= 1; i--) 
    {
        r[i] = min(r[i], r[i + 1]);
        ans -= r[i] - i;
    }
    cout << ans << '\n';

    return 0;
}

C - Prefix Mex Sequence

动态规划

记符合题目要求的序列为符合序列。

dp[i][j]表示由前i个数组成的序列中值的种类数为j的符合序列数。

S[i]=1时,第i个数只能选择前i1个数的mex,为新的数,种类数加一;

S[i]=0时,第i个数可以选择除了前i1个数的mex的所有[1,m]的数,若选择前i1个数中出现过的数,则有j种选择,若选择剩余的数,则有m+1j种选择。

状态转移方程如下:

S[i]=1,则dp[i][j]=dp[i1][j1]

S[i]=0,则dp[i][j]=dp[i1][j]j+dp[i1][j1](m+1j)

可以合成一个方程:dp[i][j]=(1S[i])dp[i1][j]j+dp[i1][j1](1+(1S[i])(mj))

答案即为j=1min(m+1,n)dp[n][j]

时间复杂度:O(nmin(n,m))

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long 

const int N = 5010, mod = 998244353;

int n, m;
int S[N];
i64 dp[N][N];

int main()
{
    cctie;
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> S[i];
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= min(m + 1, i); j++)
            dp[i][j] = ((1 - S[i]) * dp[i - 1][j] * j + dp[i - 1][j - 1] * (1 + (1 - S[i]) * (m - j))) % mod;
    i64 ans = 0;
    for (int j = 1; j <= min(m + 1, n); j++) ans += dp[n][j];
    cout << ans % mod << '\n';

    return 0;
}
posted @   会有续命晴空  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示