The 2024 ICPC Asia Hangzhou Regional Contest

Preface

去年的 hangzhou Regional,前中期对着 M 题爆写 2h 终于堪堪通过(好像说现场这题数据水了导致过了一车)

后面开始疯狂补手上会做但没写的题,最后 B 题赛后 1min 发现读入没开 long long,6 题大罚时倒闭

(平时训练 DS 一般都是我负责写的,但当时安排是让我去想 J,所以 DS 就扔给徐神了)


A. AUS

队友开场写的,我题都没看

#include <bits/stdc++.h>

bool work() {
    std::string s1, s2, s3;
    std::cin >> s1 >> s2 >> s3;
    int n = s1.size();
    if(n != s2.size()) return false;
    if(n != s3.size()) return true;
    int fa[26];
    for(int i = 0; i < 26; ++i) fa[i] = i;
    auto father = [&](int i) {
        i -= 'a';
        static std::stack<int> stack;
        while(fa[i] != i) stack.push(i), i = fa[i];
        int res = i;
        while(stack.size()) fa[stack.top()] = res, stack.pop();
        return res;
    };
    auto unon = [&](int a, int b) {
        a = father(a), b = father(b);
        if(a == b) return;
        fa[b] = a;
    };
    for(int i = 0; i < n; ++i) unon(s1[i], s2[i]);
    for(int i = 0; i < n; ++i) if(father(s1[i]) != father(s3[i])) return true;
    return false;
}

int main() {
    std::ios::sync_with_stdio(false);
    int T; std::cin >> T; while(T--) std::cout << (work() ? "YES\n" : "NO\n");
    return 0;
}


B. Barkley III

位运算一眼按位贪心,从高到低考虑二进制下每一位

如果区间内这一位上是 \(0\) 的数大于等于 \(2\) 个,则无论怎么操作这一位都是 \(0\);否则若这一位上是 \(0\) 的数为 \(0\),则无论怎么操作这一位都是 \(1\)

忽略以上两种情况后,遇到的第一个这一位上是 \(0\) 的数为 \(1\) 的情形时,删去那个数显然可以最大化答案

朴素的做法是开 \(\log a_i\) 棵线段树维护,但这题的数据范围一眼卡双 \(\log\),因此需要把每一位的信息压到一个 64 位数里

#include <bits/stdc++.h>

using llui = long long unsigned int;
constexpr int $n = 1000006;

namespace SMT {
    constexpr int $node = 4 * $n;
    llui ars[$node], hkr[$node], tag[$node];
    std::bitset<$node> isLeaf;

    void pushdown(int cur) {
        // if(isLeaf[cur]) return;
        int lc = cur << 1, rc = lc | 1;
        for(auto ch: (int[2]){lc, rc}) {
            ars[ch] &= tag[cur]; tag[ch] &= tag[cur];
            if(isLeaf[ch]) hkr[ch] = 0;
            else hkr[ch] |= ~tag[cur];
        }
        tag[cur] = ~0ull;
    }

    void pushup(int cur) {
        // if(isLeaf[cur]) return;
        int lc = cur << 1, rc = lc | 1;
        ars[cur] = ~0ull, hkr[cur] = 0;
        for(auto ch: (int[2]){lc, rc}) {
            ars[cur] &= ars[ch];
            hkr[cur] |= hkr[ch];
        }
        hkr[cur] |= ~ars[lc] & ~ars[rc];
    }

    void init(int p, int l, int r, llui *a) {
        tag[p] = ~0ull;
        if(l == r) {
            isLeaf[p] = true;
            ars[p] = a[l]; hkr[p] = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        int lc = p << 1, rc = lc | 1;
        init(lc, l, mid, a);
        init(rc, mid + 1, r, a);
        pushup(p);
    }

    void assign(int p, int l, int r, int pos, llui val) {
        if(l == r) {
            ars[p] = val; hkr[p] = 0;
            return ;
        }
        pushdown(p);
        int mid = (l + r) >> 1;
        int lc = p << 1, rc = lc | 1;
        if(pos > mid) assign(rc, mid + 1, r, pos, val);
        else          assign(lc, l, mid, pos, val);
        pushup(p);
    }

    void band(int p, int l, int r, int L, int R, llui val) {
        if(L > r || l > R) return ;
        if(L <= l && r <= R) {
            ars[p] &= val; tag[p] &= val;
            if(isLeaf[p]) hkr[p] = 0;
            else hkr[p] |= ~val;
            // std::cerr << "ars[p] = " << ars[p] << ", hkr[p] = " << hkr[p] << char(10);
            return ;
        }
        pushdown(p);
        int mid = (l + r) >> 1;
        int lc = p << 1, rc = lc | 1;
        band(lc, l, mid, L, R, val);
        band(rc, mid + 1, r, L, R, val);
        pushup(p);
    }

    void query(int p, int l, int r, int L, int R, std::vector<int> &vec) {
        if(L > r || l > R) return ;
        if(L <= l && r <= R) {
            vec.push_back(p);
            return ;
        }
        pushdown(p);
        int mid = (l + r) >> 1;
        int lc = p << 1, rc = lc | 1;
        query(lc, l, mid, L, R, vec);
        query(rc, mid + 1, r, L, R, vec);
    }

    llui ignore(int p, llui topz) {
        if(isLeaf[p]) return ~0ull;
        pushdown(p);
        int lc = p << 1, rc = lc | 1;
        if(~ars[lc] & topz) return ignore(lc, topz) & ars[rc];
        else                return ignore(rc, topz) & ars[lc];
    }
}

int n, q;
llui a[$n];

llui solve(int l, int r) {
    using namespace SMT;
    std::vector<int> vec;
    query(1, 1, n, l, r, vec);

    llui Ars = ~0ull, Hkr = 0;
    for(auto p: vec) {
        Hkr |= hkr[p];
        Hkr |= ~Ars & ~ars[p];
        Ars &= ars[p];
    }
    
    llui topz;
    if(~Hkr & ~Ars) topz = 1ull << (63 - __builtin_clzll(~Hkr & ~Ars));
    else return Ars;

    llui ans = ~0ull;
    for(auto p: vec) {
        if(~ars[p] & topz) ans &= ignore(p, topz);
        else               ans &= ars[p];
    }

    return ans;
}

void work() {
    std::cin >> n >> q;
    for(int i = 1; i <= n; i++) std::cin >> a[i];
    SMT::init(1, 1, n, a);
    while(q--) {
        int type, l, r, s;
        llui x; std::cin >> type;
        switch(type) {
            case 1:
                std::cin >> l >> r >> x;
                SMT::band(1, 1, n, l, r, x);
                break;
            case 2:
                std::cin >> s >> x;
                SMT::assign(1, 1, n, s, x);
                break;
            case 3:
                std::cin >> l >> r;
                std::cout << solve(l, r) << char(10);
                break;
        }
    }
    return ;
}

int main() {
    std::ios::sync_with_stdio(false);
    int T = 1; while(T--) work();
    return 0;
}

E. Elevator II

注意到如果我们把电梯移动到了 \(r_i\) 最大的位置,则剩下的要求都可以不消耗额外代价地完成,只需要按照 \(r_i\) 从大到小处理即可

因此问题转化为怎样用最小额外代价把电梯移动到最上面,考虑以下贪心

维护电梯当前所在楼层 \(cur\),每次找到满足 \(l_i\le cur\) 的需求中 \(r_i\) 最大的那个

若存在 \(r_i>cur\) 则直接用其更新 \(cur\);否则找一个最小的 \(l_i\),花费 \(cur-l_i\) 的代价移动过去

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<array>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,f,l[N],r[N]; array <int,3> a[N];
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d%d",&n,&f);
        long long sum=0;
        for (RI i=1;i<=n;++i)
        {
            scanf("%d%d",&l[i],&r[i]);
            a[i][0]=l[i]; a[i][1]=r[i];
            sum+=r[i]-l[i]; a[i][2]=i;
        }
        sort(a+1,a+n+1); int p=1;
        vector <int> ans;
        while (p<=n)
        {
            int nf=f,id=-1;
            while (p<=n&&a[p][0]<=f)
            {
                if (a[p][1]>nf) nf=a[p][1],id=a[p][2];
                ++p;
            }
            // printf("p = %d, id = %d, nf = %d\n",p,id,nf);
            if (id==-1)
            {
                if (p<=n)
                {
                    sum+=a[p][0]-f;
                    f=a[p][1];
                    ans.push_back(a[p++][2]);
                }
            } else
            {
                f=nf;
                ans.push_back(id);
            }
        }
        printf("%lld\n",sum);
        static int vis[N];
        for (RI i=1;i<=n;++i) vis[i]=0;
        for (auto x:ans) vis[x]=1;
        vector <array <int,3>> left;
        for (RI i=1;i<=n;++i)
        if (!vis[i]) left.push_back({l[i],r[i],i});
        auto cmp=[&](const array <int,3>& A,const array <int,3>& B)
        {
            return A[1]>B[1];
        };
        sort(left.begin(),left.end(),cmp);
        for (auto [l,r,id]:left) ans.push_back(id);
        for (auto x:ans) printf("%d ",x); putchar('\n');
    }
    return 0;
}

F. Fuzzy Ranking

把偏序关系看作一个 DAG,建图强连通分量缩点后,显然每个询问的区间对应着图上的一条链

不难发现统计答案就是找到区间内在同一个强连通分量里的点数量,直接预处理简单维护即可

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,k,q; vector <int> a[N],v[N],pre[N],suf[N]; vector <long long> pfx[N];
int dfn[N],low[N],stk[N],top,idx,vis[N],bel[N],sz[N],scc;
inline void Tarjan(CI now)
{
    dfn[now]=low[now]=++idx;
    stk[++top]=now; vis[now]=1;
    for (auto to:v[now])
    if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);
    else if (vis[to]) low[now]=min(low[now],dfn[to]);
    if (low[now]==dfn[now])
    {
        ++scc;
        do
        {
            ++sz[scc];
            bel[stk[top]]=scc;
            vis[stk[top]]=0;
        } while (stk[top--]!=now);
    }
}
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d%d%d",&n,&k,&q);
        for (RI i=1;i<=n;++i) dfn[i]=sz[i]=0,v[i].clear();
        for (RI i=1;i<=k;++i)
        {
            a[i].resize(n+1);
            for (RI j=1;j<=n;++j)
            {
                scanf("%d",&a[i][j]);
                if (j-1>=1) v[a[i][j-1]].push_back(a[i][j]);
            }
        }
        idx=scc=0;
        for (RI i=1;i<=n;++i)
        if (!dfn[i]) Tarjan(i);
        auto C2=[&](CI x)
        {
            return 1LL*x*(x-1)/2LL;
        };
        for (RI i=1;i<=k;++i)
        {
            pre[i].resize(n+1);
            suf[i].resize(n+1);
            pfx[i].resize(n+1);
            for (RI j=0;j<=n;++j) pre[i][j]=suf[i][j]=pfx[i][j]=0;
            int lst=0;
            for (RI j=1;j<=n;++j) a[i][j]=bel[a[i][j]];
            // for (RI j=1;j<=n;++j) printf("%d%c",a[i][j]," \n"[j==n]);
            for (RI j=1;j<=n;++j)
            {
                if (j==n||a[i][j]!=a[i][j+1])
                {
                    pfx[i][j]=pfx[i][lst]+C2(j-lst);
                    lst=j; pre[i][j]=suf[i][j]=j;
                }
            }
            for (RI j=1;j<=n;++j)
            if (pre[i][j]==0) pre[i][j]=pre[i][j-1];
            for (RI j=n;j>=1;--j)
            if (suf[i][j]==0) suf[i][j]=suf[i][j+1];
        }
        long long ans=0;
        while (q--)
        {
            int id,l,r; scanf("%d%d%d",&id,&l,&r);
            id=(id+ans)%k+1; l=(l+ans)%n+1; r=(r+ans)%n+1;
            // printf("id = %d, l = %d, r = %d\n",id,l,r);
            if (a[id][l]==a[id][r])
            {
                printf("%lld\n",ans=C2(r-l+1));
                continue;
            }
            int ql=suf[id][l],qr=pre[id][r];
            // printf("ql = %d, qr = %d\n",ql,qr);
            long long sum=C2(ql-l+1)+C2(r-qr);
            if (qr>ql) sum+=pfx[id][qr]-pfx[id][ql];
            printf("%lld\n",sum); ans=sum;
        }
    }
    return 0;
}

H. Heavy-light Decomposition

首先不难发现答案只和每条链的长度有关

若长度里最大值唯一,则以该链的某个端点为根,剩下的链全部挂在根下面即为合法解

否则考虑找一个长度最短的链挂在最长链某端的第二个节点上,剩下的链再挂在根下面

以上做法需要满足最短链长度小于等于最长链长度减 \(2\),不难发现这是有解的充要条件

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<array>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,k,fa[N];
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d%d",&n,&k);
        vector <array <int,3>> vec;
        for (RI i=1;i<=k;++i)
        {
            int l,r; scanf("%d%d",&l,&r);
            vec.push_back({r-l,l,r});
        }
        if (k==1)
        {
            for (RI i=vec[0][1];i<=vec[0][2];++i) printf("%d%c",i-1," \n"[i==vec[0][2]]);
            continue;
        }
        sort(vec.begin(),vec.end(),greater <array <int,3>>());
        int rt=vec[0][1];
        for (RI i=vec[0][1]+1;i<=vec[0][2];++i) fa[i]=i-1;
        fa[rt]=0;
        if (vec[1][0]==vec[0][0])
        {
            if (vec.back()[0]>vec[0][0]-2)
            {
                puts("IMPOSSIBLE");
                continue;
            }
            int heavy_son=rt+1;
            fa[vec.back()[1]]=heavy_son;
            for (RI i=vec.back()[1]+1;i<=vec.back()[2];++i) fa[i]=i-1;
            for (RI j=1;j<(int)vec.size()-1;++j)
            {
                fa[vec[j][1]]=rt;
                for (RI i=vec[j][1]+1;i<=vec[j][2];++i) fa[i]=i-1;
            }
        } else
        {
            for (RI j=1;j<(int)vec.size();++j)
            {
                fa[vec[j][1]]=rt;
                for (RI i=vec[j][1]+1;i<=vec[j][2];++i) fa[i]=i-1;
            }
        }
        for (RI i=1;i<=n;++i) printf("%d%c",fa[i]," \n"[i==n]);
    }
    return 0;
}

J. Japanese Bands

感觉思路什么的都全对,但少了一步性质的分析,可惜

考虑枚举确定两边选取的集合 \(mask_1,mask_2\),则贡献为 \(\binom{n_1-1}{|mask_1|-1}\times \binom{n_2-1}{|mask_2|-1}\),现在考虑怎样的 \(mask_1,mask_2\) 是符合要求的

一个显著的观察是对于任意 \(\{a_i,b_i\}\)\(mask_1\cap\{a_i,b_i\}\ne \emptyset\and mask_2\cap\{a_i,b_i\}\ne \emptyset\),否则这条限制一定无法满足

但直接这么判会漏掉一种 Case,例如 \(mask_1,mask_2\) 中都仅包含了 \(a_i\) 而不包含 \(b_i\)

不难发现可以加一条 \(mask_1\cup mask_2=\bigcup \{a_i,b_i\}\) 来 fix 这种情况,现在考虑如何计数

考虑枚举确定 \(mask_2\) 时,根据最后一条 rule,合法的 \(mask_1\) 一定是某个状态的超集,用 sosdp 处理之即可

总复杂度 \(O(m2^m)\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int M=20,mod=1e9+7;
int t,n1,n2,m,k,ifac[M+5],f[1<<M],g[1<<M],cnt[1<<M];
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(void)
{
	for (RI i=0;i<=20;++i) ifac[i]=quick_pow(i);
	for (RI i=0;i<(1<<20);++i) cnt[i]=cnt[i>>1]+(i&1);
}
inline int C(CI n,CI m) //m<=20
{
	if (n<0||m<0||n<m) return 0;
	int res=1;
	for (RI i=1;i<=m;++i) res=1LL*res*(n-i+1)%mod*ifac[i]%mod;
	return res;
}
int main()
{
	for (init(),scanf("%d",&t);t;--t)
	{
		scanf("%d%d%d%d",&n1,&n2,&m,&k);
		for (RI i=0;i<(1<<m);++i) f[i]=g[i]=0;
		int all=0;
		for (RI i=1;i<=k;++i)
		{
			int x,y; scanf("%d%d",&x,&y);
			--x; --y; all|=(1<<x)|(1<<y);
			g[(1<<x)|(1<<y)]=1;
		}
		for (RI i=0;i<m;++i)
		for (RI mask=0;mask<(1<<m);++mask)
		if (((mask>>i)&1)==1) g[mask]|=g[mask^(1<<i)];
		for (RI mask=0;mask<(1<<m);++mask)
		if (!g[mask^((1<<m)-1)]) f[mask]=C(n1-1,cnt[mask]-1);
		for (RI i=0;i<m;++i)
		for (RI mask=0;mask<(1<<m);++mask)
		if (((mask>>i)&1)==0) (f[mask]+=f[mask^(1<<i)])%=mod;
		int ans=0;
		for (RI mask=0;mask<(1<<m);++mask)
		if (!g[mask^((1<<m)-1)])
		(ans+=1LL*C(n2-1,cnt[mask]-1)*f[all^(all&mask)]%mod)%=mod;
		printf("%d\n",ans);
	}
	return 0;
}

K. Kind of Bingo

签到,枚举最后先填完的是哪一行,贪心地每次把最大的元素换出去即可,总复杂度 \(O(nm)\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,m,k; vector <int> pos[N];
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d%d%d",&n,&m,&k);
        for (RI i=1;i<=n;++i) pos[i].clear();
        for (RI i=1;i<=n*m;++i)
        {
            int x; scanf("%d",&x);
            pos[(x-1)/m+1].push_back(i);
        }
        int ans=1e9;
        for (RI i=1;i<=n;++i)
        {
            sort(pos[i].begin(),pos[i].end(),greater <int>());
            // for (auto x:pos[i]) printf("%d ",x); putchar('\n');
            static int vis[N]; int mex=1;
            for (auto x:pos[i]) vis[x]=1;
            for (RI j=0;j<min(k,m);++j)
            {
                while (vis[mex]) ++mex;
                if (pos[i][j]<mex) break;
                vis[mex]=1; vis[pos[i][j]]=0;
                pos[i][j]=mex;
            }
            // for (auto x:pos[i]) printf("%d ",x); putchar('\n');
            ans=min(ans,*max_element(pos[i].begin(),pos[i].end()));
            for (RI j=1;j<=mex;++j) vis[j]=0;
            for (auto x:pos[i]) vis[x]=0;
        }
        printf("%d\n",ans);
    }
    return 0;
}

M. Make It Divisible

感觉我们队做法复杂了,很难想象一个铜牌题要写笛卡尔树+Pollard_Rho,但你就说过没过吧

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

const int N = 5e4+5;
int n, k, b[N], fa[N], id[N];
LL ans;

struct Node {
    int l, r, f;
    bool operator<(const Node &a) const {return r < a.l;}
};
vector <int> vec2;
set<Node> st;
bool all = true;

// vector<int> pro(int x) {
//     // printf("x=%d\n", x);
//     vector<int> vec;
//     for (int i=1; i*i<=x; ++i) {
//         if (x%i == 0) {
//             vec.push_back(i);
//             if (x/i != i) vec.push_back(x/i);
//         }
//     }
//     sort(vec.begin(),vec.end());
//     return vec;
// }

#define RI register int
#define CI const int&
namespace Pollard_Rho
{
    inline int sum(CI x,CI y,CI mod)
    {
        return x+y>=mod?x+y-mod:x+y;
    }
    inline int sub(CI x,CI y,CI mod)
    {
        return x-y<0?x-y+mod:x-y;
    }
    inline int quick_pow(int x,int p,int mod,int mul=1)
    {
        for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
    }
    inline bool Miller_Robin(CI n)
    {
        if (n<=1) return 0;
        vector <int> base={2,3,5,7,11,13,17,19,23};
        for (auto x:base)
        {
            if (n==x) return 1;
            if (n%x==0) return 0;
        }
        int m=(n-1)>>__builtin_ctz(n-1);
        for (auto x:base)
        {
            int t=m,a=quick_pow(x,m,n);
            while (t!=n-1&&a!=1&&a!=n-1) a=1LL*a*a%n,t*=2;
            if (a!=n-1&&t%2==0) return 0;
        }
        return 1;
    }
    inline int get_frac(CI n)
    {
        if (n%2==0) return 2;
        auto f=[&](CI x)
        {
            return sum(1LL*x*x%n,1,n);
        };
        int x=0,y=0,tot=0,p=1,q,g;
        for (int i=0;(i&0xff)||(g=__gcd(p,n))==1;++i,x=f(x),y=f(f(y)))
        {
            if (x==y) x=tot++,y=f(x);
            q=1LL*p*sub(x,y,n)%n;
            if (q) p=q;
        }
        return g;
    }
    inline vector <int> solve(CI n)
    {
        if (n==1) return {};
        if (Miller_Robin(n)) return {n};
        int d=get_frac(n);
        auto v1=solve(d),v2=solve(n/d);
        auto i1=v1.begin(),i2=v2.begin();
        vector <int> ans;
        while (i1!=v1.end()||i2!=v2.end())
        {
            if (i1==v1.end()) ans.push_back(*i2++);
            else if (i2==v2.end()) ans.push_back(*i1++);
            else ans.push_back(*i1<*i2?*i1++:*i2++);
        }
        return ans;
    }
}

inline void DFS(CI now,int mul,vector <pair <int,int>>& num,vector <int>& res)
{
    if (now>=(int)num.size())
    {
        res.push_back(mul);
        return;
    }
    DFS(now+1,mul,num,res);
    for (RI i=1;i<=num[now].second;++i)
    mul*=num[now].first,DFS(now+1,mul,num,res);
}

void calc(int a, int b) {
    // printf("a=%d b=%d\n", a, b);
    vector<int> res = Pollard_Rho::solve(b-a);
    vector<pair <int,int>> num;
    int lst=-1,cnt=1;
    for (auto x:res)
    {
        if (x!=lst)
        {
            if (lst!=-1) num.push_back({lst,cnt});
            cnt=1;
        } else ++cnt;
        lst=x;
    }
    num.push_back({lst,cnt});
    vector <int> frac;
    DFS(0,1,num,frac);
    sort(frac.begin(),frac.end());
    // vector<int> vec = pro(b-a);
    // printf("vec:"); for (int x : vec) printf("%d ", x); puts("");
    vector <int> vec1;
    for (int x : frac) if (x > a && x-a <= k) vec1.push_back(x-a);
    // printf("st1:"); for (int x : st1) printf("%d ", x); puts("");
    // printf("11111\n");
    
    if (all) {
        swap(vec2, vec1);
    } else {
        vector <int> tmp;
        if (vec2.size() > vec1.size()) swap(vec2, vec2);
        int p=0;
        for (auto x : vec2) {
            while (p<(int)vec1.size()&&vec1[p]<x) ++p;
            if (p<(int)vec1.size()&&vec1[p]==x) tmp.push_back(x);
        }
        swap(tmp, vec2);
    }
    all = false;
    // printf("st2:"); for (int x : st2) printf("%d ", x); puts("");
}

void solve() {
    cin >> n >> k;
    for (int i=1; i<=n; ++i) cin >> b[i], id[i]=i;
    sort(id+1, id+n+1, [&](int aa, int bb){return b[aa]<b[bb];});
    st.clear();
    st.insert(Node{1, n, -1});
    for (int i=1; i<=n; ++i) {
        int x = id[i];
        auto it = st.find(Node{x, x, -1});
        auto [l, r, f] = *it;
        st.erase(it);
        fa[x] = f;
        if (x > l) st.insert(Node{l, x-1, x});
        if (x < r) st.insert(Node{x+1, r, x});
    }

    vec2.clear();
    all=true;
    for (int i=1; i<=n; ++i) if (fa[i]!=-1) {
        // printf("i=%d\n", i);
        if (b[fa[i]] == b[i]) continue;
        calc(b[fa[i]], b[i]);
    }

    ans = 0;
    if (all) {
        ans = 1LL*(k+1)*k/2;
        cout << k << ' ' << ans << '\n';
    } else {
        for (auto x : vec2) ans += x;
        cout << vec2.size() << ' ' << ans << '\n';
    }
}

signed main() {
    ios::sync_with_stdio(0); cin.tie(0);
    // vector<int> res = Pollard_Rho::solve(24);
    // vector<pair <int,int>> num;
    // int lst=-1,cnt=1;
    // for (auto x:res)
    // {
    //     if (x!=lst)
    //     {
    //         if (lst!=-1) num.push_back({lst,cnt});
    //         cnt=1;
    //     } else ++cnt;
    //     lst=x;
    // }
    // num.push_back({lst,cnt});
    // vector <int> frac;
    // DFS(0,1,num,frac);
    // sort(frac.begin(),frac.end());
    // for (auto x:frac) printf("%d ",x); putchar('\n');
    int T; cin >> T; while (T--) solve();
    return 0;
}

Postscript

如果这场正常点打估计能场上勉强过个 B 苟个 7 题尾?

这么看来确实印证了去年选站的大失败,除了沈阳和昆明感觉剩下的站都能 Au 啊,今年能弥补下遗憾吗

posted @ 2025-10-18 14:42  空気力学の詩  阅读(2)  评论(0)    收藏  举报