The 2026 ICPC Asia East Continent Online Contest (I) 题解

The 2026 ICPC Asia East Continent Online Contest (I)

A. Recall

给定丢失所有弹栈操作后的序列,在其中插入若干 -,使栈内元素始终互异且所有 T/F 询问正确,输出任意合法操作序列。

首先,如果没有 T 操作,进一个弹一个一定没有问题。

如果有 T 操作,那么形如 [+x...Tx],对于每一个 + 操作,记录每个 + 操作需要存活到第几轮,然后维护栈,栈顶元素不需要存活了就弹出。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
    int n;
    cin >> n;
    vector <char> op(n + 1);
    vector <int> x(n + 1);
    for(int i = 1; i <= n; i ++ )
        cin >> op[i] >> x[i];
    map <int, int> lstT;
    vector <int> need(n + 1);
    for(int i = n; i >= 1; i -- )
    {
        if(op[i] == 'T')
        {
            if(lstT[x[i]] == 0)
                lstT[x[i]] = i;
        }
        if(op[i] == '+')
        {
            need[i] = max(i, lstT[x[i]]);
            lstT[x[i]] = 0;
        }
    }
    // for(int i = 1; i <= n; i ++ )
    //     cerr << need[i] << " ";
    // cerr << "\n";
    stack <int> s;
    vector <char> ans;
    for(int i = 1; i <= n; i ++ )
    {
        while(!s.empty() and need[s.top()] < i)
        {
            ans.push_back('-');
            s.pop();
        }
        if(op[i] == '+')
        {
            ans.push_back('+');
            s.push(i);
        }
        else
        {
            ans.push_back('?');
        }
    }
    for(auto c : ans)
        cout << c;
    cout << "\n";
}

int main()
{
    int T; cin >> T;
    while(T -- ) solve();
}

C. Permutation Inversions

给定若干个区间内下标对应值的大小关系 ,构造一个满足所有关系的排列,使逆序对数量最少 ;无解输出 -1

小的元素尽量前,大的元素尽量后。拓扑找关系即可,每次找一段里最大的 / 最小的尽量往后 / 往前放。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
    int n, m;
    cin >> n >> m;
    vector <int> covered(n + 1);
    vector <vector<int>> G(n + 1);
    vector <int> deg(n + 1); 
    for(int i = 1; i <= m; i ++ )
    {
        int l, r;
        cin >> l >> r;
        for(int j = l; j <= r; j ++ )
            covered[j] = 1;
        int lst;
        for(int j = 1; j <= r-l+1; j ++ )
        {
            int x;
            cin >> x;
            if(j > 1)
            {
                G[x].push_back(lst);
                deg[lst] ++ ;
            }
            lst = x;
        }
    }
    vector <int> ans(n + 1);
    priority_queue <int> q;
    for(int i = 1; i <= n; i ++ )
    {
        if(!covered[i]) ans[i] = i;
        else
        {
            int j = i;
            while(j <= n and covered[j]) j ++ ;
            for(int k = i; k < j; k ++ )
                if(!deg[k])
                    q.push(k);
            int mx = j - 1;
            while(!q.empty())
            {
                int u = q.top(); q.pop();
                if(ans[u]) {cout << "-1\n"; return ;}
                ans[u] = mx; mx -- ;
                for(auto v : G[u])
                {
                    deg[v] -- ;
                    if(deg[v] == 0) q.push(v);
                }
            }
            for(int k = i; k < j ; k ++ )
            {
                if(!ans[k]) {cout << "-1\n"; return ;}
            }
            i = j - 1;
        } 
    }
    for(int i = 1; i <= n; i ++ ) cout << ans[i] << " ";
    cout << "\n";
}
signed main()
{
    int T; cin >> T;
    while(T -- ) solve();
}

D. Sequence

给你一个长度为 nnn 的 01 串 sss 中,每个位置 iii 前缀里与 sis_isi 不同的字符个数 pip_ipi 的乱序集合 。求有多少个 01 串能产生这个 ppp 集合。

主要是怎么处理 ppp 是乱序集合。

对于第 iii 位,如果与 i−1i-1i−1 位相同,则 pi=pi−1p_i = p_{i-1}pi=pi−1;如果与 i−1i-1i−1 位不同,则 pi=i−1−pip_i = i-1-p_ipi=i−1−pi。

记 pip_ipi 两种选择,记为 x,yx, yx,y。

不妨前 i−1i-1i−1 位有 xxx 个 000 和 yyy 个 111。

若 x=yx=yx=y,两种选择随便。

若 x<yx < yx<y 且 x∈Px \in Px∈P,则 sis_isi 必选 111。若选 000,则 pi=yp_i = ypi=y,下一手局面变为 x+1x+1x+1 个 000 和 yyy 个 111,x+1,yx+1,yx+1,y 均大于 xxx,PPP 中再也不会出现 xxx。

也就是说如果小的在 PPP 中,pip_ipi 必定是小的。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int main()
{
    int n;
    cin >> n;
    vector <int> cntp(n + 1), p(n + 1);
    for(int i = 1; i <= n; i ++ )
    {
        int x;
        cin >> x;
        cntp[x] ++ ;
    }
    long long ans = 1;
    for(int i = 1; i <= n; i ++ )
    {
        int x = p[i-1], y = i-1-p[i-1];
        if(x > y) swap(x, y);
        if(x == y) ans = ans * 2 % mod;
        if(cntp[x] > 0)
        {
            p[i] = x;
            cntp[x] -- ;
        }
        else
        {
            p[i] = y;
            cntp[y] -- ;
        }
    }
    cout << ans;
}

L. Longest Common Prefix

每加入一个字符串,对前 iii 个字符串的每个 jjj,求任选 jjj 个串能得到的最大 LCP 长度 fi,jf_{i,j}fi,j,输出:

∑j=1i(fi,j⊕j). \sum_{j=1}^{i}(f_{i,j}\oplus j). j=1∑i(fi,j⊕j).

考虑从第 i−1i-1i−1 轮到第 iii 轮的变化。

Trie 上会新增一条路径,对于节点 cntcntcnt 从 c→c+1c \to c+1c→c+1,只可能对 fc+1f_{c+1}fc+1 产生影响,新的可能贡献为 depu⊕(c+1)dep_u \oplus (c+1)depu⊕(c+1)。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int son[N][26], cnt[N], dep[N], f[N];
int main() 
{
    int n;
    cin >> n;
    int tot = 0;
    long long ans = 0;
    for(int i = 1; i <= n; i ++ )
    {
        string s;
        cin >> s;
        int u = 0;
        ans += i;
        for(char c : s)
        {
            int &v = son[u][c-'a'];
            if(!v)
            {
                v = ++ tot;
                dep[v] = dep[u] + 1;
            }
            u = v;
            cnt[u] ++ ;
            if(u and dep[u] > f[cnt[u]])
            {
                ans -= f[cnt[u]] ^ cnt[u];
                ans += dep[u] ^ cnt[u];
                f[cnt[u]] = dep[u];
            }
        }
        cout << ans << "\n";
    }
}
相关推荐
fpcc2 小时前
c++编程实践—统一初始化
服务器·c++
Zenova EdgeOS3 小时前
C++ 工业边缘 libcurl HTTP 客户端实战
开发语言·c++·网络协议·边缘计算
Jackson_GJH4 小时前
Qt 右键自定义菜单的实现
开发语言·c++·qt
张小姐的猫4 小时前
【AI大模型接入SDK】 —— Gemini接入封装
android·数据结构·数据库·c++·人工智能·python
一木 之林4 小时前
七、一-AI 工程实践、插件化调试与软件交付
java·linux·c++
Murphy_lx6 小时前
1124. 表现良好的最长时间段
c++·算法
luj_17688 小时前
一线一区一变破解人盯人防守密码
开发语言·网络·c++·经验分享·算法
广州山泉婚姻8 小时前
C/C++动态内存:堆内存的申请、使用与释放
c++·人工智能
Jackson_GJH9 小时前
日志_图解spdlog
开发语言·c++