AGC038 题解

[AGC038A] 01 Matrix

题意

构造一个 \(n\times m\) 矩阵,满足对于每一行,\(\min(cnt_0,cnt_1)=a\),对于每一列 \(\min(cnt_0,cnt_1)=b\),或报告无解。

\(n,m\le 10^3,0\le 2a \le n,0\le 2b \le m\)

idea

简单构造。

取前 \(b\) 行,每行先放 \(a\)\(0\),再放 \(m-a\)\(1\)
取后 \(n-b\) 行,每行先放 \(a\)\(1\),再放 \(m-a\)\(0\)

Code

#include<bits/stdc++.h>
#define ll long long
#define N 200005
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-6;
ll n,m,x,y;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n>>m>>x>>y;
    for(int i=1;i<=y;i++){
        for(int j=1;j<=x;j++)cout<<0;
        for(int j=x+1;j<=m;j++)cout<<1;
        cout<<endl;
    }
    for(int i=y+1;i<=n;i++){
        for(int j=1;j<=x;j++)cout<<1;
        for(int j=x+1;j<=m;j++)cout<<0;
        cout<<endl;
    }
    return 0;
} 

[AGC038B] Sorting a Segment

题意

给定长为 \(n\) 的排列,问对恰好一个长为 \(k\) 的区间升序排序,最后可能的本质不同序列是多少。

idea

如果一个长为 \(k\) 的区间本来就是升序,排序完不变,这种情况只统计一次答案。

对于不完全升序的情况,考虑什么情况下,两个区间排序后仍然相同。

设第一个排序区间为 \([i,i+k-1]\),第二个与其有交的排序区间为 \([j,j+k-1]\),如果他们排序后相同,当且仅当 \([i,j-1]\)\([i+k,j+k-1]\) 在排序后均不会改变位置。

如果 \([j,j+k-1]\)\([i,i+k-1]\) 排序后相同,那么一定有 \([j-1,j+k-2]\)\([i,i+k-1]\) 相同。 考虑取 \(j=i+1\),只需要判断 \(a_i\) 是区间最小值,\(a_{i+k}\) 是区间最大值即可。

总结

  • 重要观察:两区间重排后相等的条件。

Code

#include<bits/stdc++.h>
#define ll long long
#define N 800005
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-6;

ll n,k,a[N];
ll l[N],sum[N];
struct sgt{
    #define mid ((l+r)>>1)
    #define ls (p<<1)
    #define rs (p<<1|1)
    ll mx[N],lzy[N],mi[N];
    void build(ll p,ll l,ll r){
        if(l==r){
            mx[p]=a[l];
            mi[p]=a[l];
            return ;
        }
        build(ls,l,mid);
        build(rs,mid+1,r);
        mx[p]=max(mx[ls],mx[rs]);
        mi[p]=min(mi[ls],mi[rs]);
    }
    ll qrmax(ll p,ll l,ll r,ll le,ll ri){
        if(le<=l&&ri>=r)return mx[p];
        ll ans=-inf;
        if(le<=mid)ans=max(ans,qrmax(ls,l,mid,le,ri));
        if(ri>mid)ans=max(ans,qrmax(rs,mid+1,r,le,ri));
        return ans;
    }
    ll qrmin(ll p,ll l,ll r,ll le,ll ri){
        if(le<=l&&ri>=r)return mi[p];
        ll ans=inf;
        if(le<=mid)ans=min(ans,qrmin(ls,l,mid,le,ri));
        if(ri>mid)ans=min(ans,qrmin(rs,mid+1,r,le,ri));
        return ans;
    }
}T;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    T.build(1,1,n);
    l[0]=inf;
    for(int i=1;i<=n;i++)l[i]=min(l[i-1],a[i]);
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+(a[i]<a[i-1]);
    ll res=0;
    ll p=1;
    for(int i=1;i+k-1<=n;i++){
        if(sum[i+k-1]-sum[i]==0){
            res+=p,p=0;
            continue;
        }
        if(T.qrmin(1,1,n,i,i+k-1)==a[i]&&T.qrmax(1,1,n,i+1,i+k)==a[i+k])continue;
        res++;
    }
    cout<<res<<endl;
    return 0;
}

[AGC038C] LCMs

题意

求:

\[\large\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n \text{lcm}(a_i,a_j) \]

idea

推公式后莫比乌斯反演板题。

\[\large\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n \text{lcm}(a_i,a_j)=\frac{1}{2}\sum\limits_{i=1}^n\sum\limits_{j=1}^n \text{lcm}(a_i,a_j)-\sum\limits_{i=1}^na_i \]

开始推公式:

\[\Large \begin{align*} \sum\limits_{i=1}^n\sum\limits_{j=1}^n \text{lcm}(a_i,a_j) &=\sum\limits_{i=1}^n\sum\limits_{j=1}^n\frac{a_ia_j}{\gcd(a_i,a_j)}\\ &=\sum\limits_{i=1}^n\sum\limits_{j=1}^n \frac{ic_i\cdot jc_j}{\gcd(i,j)}\\ &=\sum\limits_{d=1}^n\sum\limits_{i=1}^n\sum\limits_{j=1}^n \frac{ic_i\cdot j c_j}{d}[\gcd(i,j)==d]\\ &=\sum\limits_{d=1}^nd\sum\limits_{i=1}^{\left\lfloor \frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{d}\right\rfloor} ic_{id}\cdot jc_{jd}[\gcd(i,j)==1]\\ &=\sum\limits_{d=1}^nd\sum\limits_{x=1}^{\left\lfloor \frac{n}{d}\right\rfloor}x^2\mu(x)\sum\limits_{i=1}^{\left\lfloor \frac{n}{dx}\right\rfloor}ic_{idx}\sum\limits_{j=1}^{\left\lfloor \frac{n}{dx}\right\rfloor} \cdot jc_{jdx}\\ &=\sum\limits_{d=1}^nd\sum\limits_{x=1}^{\left\lfloor \frac{n}{d}\right\rfloor}x^2\mu(x)\left(\sum\limits_{i=1}^{\left\lfloor \frac{n}{dx}\right\rfloor}ic_{idx}\right)^2\\ &=\sum\limits_{T=1}^n T\sum\limits_{x|T}x\mu(x)\left(\sum\limits_{i=1}^{\left\lfloor \frac{n}{T}\right\rfloor}ic_{iT}\right)^2\\ \end{align*} \]

中间后面都可以枚举倍数刷表做,时间复杂度 \(O(n\log n)\)

总结

  • 写公式累死了。
  • 重要化简:把 \(a_i\) 转化为 \(i\cdot c_i\)

Code

#include<bits/stdc++.h>
#define ll long long
#define N 1000005
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double eps=1e-6;
ll mu[N],smu[N],phi[N],f[N],g[N];
bool vis[N];
vector<ll>prim;
ll fpow(ll x,ll y){
    ll res=1;
    while(y){
        if(y&1)res=res*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return res;
}
void init(ll n){
    mu[1]=phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            mu[i]=-1;
            phi[i]=i-1;
            prim.push_back(i);
        }
        for(auto j:prim){
            if(i*j>n)break;
            vis[i*j]=1;
            if(i%j==0){
                phi[j*i]=phi[i]*j;
                mu[j*i]=0;
                break;
            }
            phi[j*i]=phi[i]*phi[j];
            mu[j*i]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)for(int j=1;i*j<=n;j++)g[i*j]+=mu[i]*i;
}
ll sold(ll n){
    ll res=0;
    for(int x=1;x<=n;x++)res=(res+x*g[x]%mod*f[x]%mod*f[x]%mod+mod)%mod;
    return res;
}
ll n,m,a[N],mp[N];
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n;
    ll sum=0,m=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mp[a[i]]++;
        sum=(sum+a[i])%mod;
        m=max(m,a[i]);
    }
    init(m);
    for(int i=1;i<=m;i++)for(int j=1;i*j<=m;j++)f[i]=(f[i]+mp[i*j]*j%mod)%mod;
    ll res=sold(m);
    cout<<(res-sum+mod)%mod*fpow(2,mod-2)%mod;
    return 0;
}

[AGC038D] Unique Path

题意

有一张联通图 \(n\) 个点 \(m\) 条边。

给定 \(Q\) 条限制,每条限制形如\(A_i,B_i,C_i\)

\(C_i = 0\),则 \(A_i\)\(B_i\) 仅有一条简单路径。

\(C_i=1\),则 \(A_i\)\(B_i\) 有多条简单路径。

判定在这 \(Q\) 条限制下能否构造出合法的图。可以输出 Yes,否则输出 No

\(n,Q\le 10^5,m\le \frac{n(n-1)}{2}\)

idea

考虑若 \(a\rightarrow b\) 简单路径唯一, \(b\rightarrow c\) 路径唯一,则 \(a\rightarrow c\) 简单路径唯一,具有传递性,考虑用并查集维护,得到 \(k\) 个连通块。

然后不会连多条路径的边了。

Sol

如果没有多条简单路径的限制的情况:

  • 最小连边数量为 \(k-1\),这是为了保证图连通。

  • 最大连边数量为 \(\frac{k(k-1)}{2}\),由于同一个连通块不可能有两个点连向同一个连通块,所以只取每个连通块的一个点作为代表,这 \(k\) 个点两两相连。

如果有多条简单路径的限制的情况:

  • 如果简单路径不唯一的点位于同一个连通块无解。

  • 只有两个连通块无解,无论如何也不满足条件。

  • 最小连边数量为 \(k\),在保证图连通的基础上,要求多条简单路径,每个连通块的代表点构成环。

  • 最大连边数量仍然为 \(\frac{k(k-1)}{2}\)

只需要判断 \(m\) 条边够用且能用完即可。

总结

  • 重要观察 \(1\):简单路径唯一的传递性。
  • 重要观察 \(2\):连边数量的上下界。

Code

#include<bits/stdc++.h>
#define ll long long
#define N 100005
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-6;

int n;
ll k,m;
int q;
int fa[N];
int fd(ll x){
    return fa[x]==x?fa[x]:fd(fa[x]);
}
void mer(ll x,ll y){
    x=fd(x),y=fd(y);
    if(x==y)return ;
    fa[y]=x;
}
vector<pair<ll,ll> >v;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=q;i++){
        ll x,y,op;
        cin>>x>>y>>op;
        x++,y++;
        if(op==0)mer(x,y);
        else v.push_back({x,y});
    }
    for(int i=1;i<=n;i++)if(fa[i]==i)k++;
    if(k==2&&v.size()){
        cout<<"No\n";
        return 0;
    }
    for(auto [x,y]:v){
        if(fd(x)==fd(y)){
            cout<<"No\n";
            return 0;
        }
    }
    m-=(n-k);
    if(m<k-(v.empty())){
        cout<<"No\n";
        return 0;
    }
    if(k*(k-1)/2<m){
        cout<<"No\n";
        return 0;
    }
    cout<<"Yes\n";
    return 0;
}

[AGC038E] Gachapon

题意

一个随机数生成器,生成 \([1,n]\) 之间的整数,其中生成 \(i\) 的概率为 \(\frac{A_i}{\sum A_i}\)

\(\forall i\in[1,n]\)\(i\) 至少出现了 \(B_i\) 次时,停止生成,否则继续生成。

求期望生成随机数的次数,输出答案对 \(998244353\) 取模的结果。

\(a_i,b_i\geq 1\)\(\sum a_i,\sum b_i,n\leq 400\)

idea

一眼 \(\text{min-max}\) 容斥,考虑如下式子:

\[\large E(\max U)=\sum\limits_{S\subseteq U}(-1)^{|S|+1}E(\min S) \]

\(E(\min S)\) 表示 \(S\) 集合内至少有一个元素生成规定次数的期望时间,求出这个即可求出答案。但是我不会求

Sol

令 $ A=\sum\limits_{i=1}^n a_i,A_S=\sum\limits_{i\in S}a_i$,选到 \(S\) 集合内的元素的期望次数是 \(\frac{A}{A_S}\),于是我们可以认为每 \(\frac{A}{A_S}\) 次让 \(S\) 集合内的某个元素增加,现在只需要考虑集合内的元素即可。

\(E(\min S)\) 不好算,考虑拆成概率,设 \(P(X=i)\) 表示进行了 \(i\) 次集合内操作后,恰好有一个位置刚好达到目标的概率:

\[\large E(\min S)=\frac{A}{A_S}\sum\limits_{i=1}^{\infty} iP(X=i)=\frac{A}{A_S}\sum\limits_{i=1}^{\infty}\sum\limits_{j=i}^{\infty} P(X=j)=\frac{A}{A_S}\sum\limits_{i=1}^{\infty} P(X\ge i) \]

考虑 \(P(X\ge i)\) 的实际意义:至少 \(i\) 次集合内操作后,恰好有一个位置刚好达到目标的概率,等价于 \(i-1\) 次集合内操作时没有一个位置实现目标的概率

\(x_i\) 满足 \(i\in S,x_i\in[0,b_i)\),表示当前目标加了几次,则有 \(X=\sum\limits_{i\in S}x_i\),我们需要计算的就是 \(X\) 次集合内操作后,\(i\) 位置上为 \(\{x_i\}\) 的概率,设其为 \(P(x_i)\)

\[\large P(x_i)=\prod_{i\in S}\left(\frac{a_i}{A_S}\right)^{x_i} \frac{X!}{x_i} \]

实际意义:选到 \(x_i\)\(i\) 位置,并对其进行多重集的排序。
于是我们可以得到:

\[\large E(\min S)=\frac{A}{A_S}X!\sum\limits_{i\in S,x_i\in[0,b_i)} \prod\limits_{i\in S}\left(\frac{a_i}{A_S}\right)^{x_i}\frac{1}{x_i!} \]

于是有:

\[\large\begin{align*} E(\max U)&=\sum\limits_{S\subseteq U} \frac{A}{A_S} (-1)^{|S|+1}X!\sum\limits_{i\in S,x_i\in[0,b_i)} \prod\limits_{i\in S}\left(\frac{a_i}{A_S}\right)^{x_i}\frac{1}{x_i!}\\ &=A\sum\limits_{S\subseteq U} (-1)^{|S|+1}\frac{X!}{(A_S)^{X+1}} \sum\limits_{i\in S,x_i\in[0,b_i)} \prod\limits_{i\in S}\frac{a_i^{x_i}}{x_i!}\\ &=A\sum\limits_{S\subseteq U} (-1)\frac{X!}{(A_S)^{X+1}} \sum\limits_{i\in S,x_i\in[0,b_i)}\prod\limits_{i\in S}(-1)\times \frac{a_i^{x_i}}{x_i!} \end{align*}\]

考虑计算右边那坨东西,设 \(f[i][j][k]\) 表示考虑由前 \(i\) 个元素,当前集合的 \(A_S=j,X=k\) 的对答案贡献和。

初始化 \(f[0][0][0]=1\)
有转移:
如果 \(i\) 不选:

\[\large f[i+1][j+a_{i+1}][k+d]=f[i+1][j+a_{i+1}][k+d]+f[i][j][k] \]

如果 \(i\) 选,需要满足 \(d< b_{i+1}\)

\[\large f[i+1][j+a_{i+1}][k+d]=f[i+1][j+a_{i+1}][k+d]-(a_{i+1} )^d\times\frac{1}{d!}\times f[i][j][k] \]

答案为:

\[\large E(\max U)=A\sum\limits_{i=1}^A \sum\limits_{j=1}^B (-1)\frac{j!}{i^{j+1}}f[n][i][j] \]

时间复杂度 \(O(nAB)\)

总结

  • 题解写的好抽象,理解了两天半。
  • 重要观察 \(1\):期望转化概率,通过实际意义再次转化。
  • 重要观察 \(2\):枚举集合贡献用 dp 求解。

Code

#include<bits/stdc++.h>
#define ll long long
#define N 405
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double eps=1e-6;
ll n,a[N],b[N];

ll f[N][N][N];
namespace math_permutation{
    ll fpow(ll x,ll y){
        ll res=1;
        while(y){
            if(y&1)res=res*x%mod;
            y>>=1,x=x*x%mod;
        }
        return res;
    }
    ll fac[N],ifac[N],inv[N];
    void work(ll r){
        fac[0]=inv[1]=1;
        for(int i=1;i<=r;i++)fac[i]=fac[i-1]*i%mod;
        ifac[r]=fpow(fac[r],mod-2);
        for(int i=r;i>0;i--){
            ifac[i-1]=ifac[i]*i%mod;
            inv[i]=fac[i-1]*ifac[i]%mod;
        }
    }
    ll C(ll n,ll m){
        if(n<0||n<m)return 0;
        return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    void add(ll &x,ll y){
        x%=mod,y%=mod;
        x=(x+y+mod)%mod;
    }
}using namespace math_permutation;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n;
    work(400);
    f[0][0][0]=1;
    ll A=0,B=0;
    for(int i=0,a,b;i<n;i++){
        cin>>a>>b;
        for(int j=0;j<=A;j++){
            for(int k=0;k<=B;k++){
                if(f[i][j][k]==0)continue;
                add(f[i+1][j][k],f[i][j][k]);
                for(int l=0;l<b;l++){
                    add(f[i+1][j+a][k+l],-1*ifac[l]*fpow(a,l)%mod*f[i][j][k]%mod);
                }
            }
        }
        A+=a,B+=b;
    }
    ll res=0;
    for(int i=0;i<=A;i++){
        for(int j=0;j<=B;j++){
            ll p=fpow(i,j+1);
            add(res,-fac[j]*fpow(p,mod-2)%mod*f[n][i][j]%mod);
        }
    }
    res=res*A%mod;
    cout<<res<<endl;
    return 0;
}

[AGC038F] Two Permutations

题意

两个 \([1,n]\) 的排列 \(P_i,Q_i\),构造两组排列满足:

  • \(A_i=P_i\)\(A_i=i\)
  • \(B_i=Q_i\)\(B_i=i\)

最大化 $ \sum\limits_{i=1}^n[A_i\neq B_i]$。

idea

最大化 $ \sum\limits_{i=1}^n[A_i\neq B_i]$,相当于最大化 \(n- \sum\limits_{i=1}^n[A_i=B_i]\),即最小化 \(\sum\limits_{i=1}^n[A_i=B_i]\)

感觉题目限制很像网络流,考虑如何建图。

注意到由于排列会形成若干个度数均为 \(2\) 的环,对于一个环上的点如果取 \(A_i=i\),那么整个环都要跟着一起取,如果取 \(A_i=P_i\),整个环仍然要跟着一起取。

但是不会建图,情况有点多。

Sol

对于 \(P_i\) 形成的环称为 \(p_i\) ,对于 \(Q_i\) 形成的环称为 \(q_i\),称使 \(A_i=P_i\) 的操作为旋转。

设源点 \(S\) 和汇点 \(T\) ,若存在 \(S\rightarrow p_i\)\(p_i\) 旋转,\(q_i\rightarrow T\)\(q_i\) 旋转。

考虑分情况讨论使最后 \(A_i=B_i\)

  • \(P_i=Q_i=i\),无论如何都有 \(A_i=B_i\),需要特判。
  • \(P_i=i,Q_i\neq i\)\(p_i\) 随便取,\(q_i\) 不旋转,连边 \(q_i\rightarrow T\) 表示割掉该边后 \(q_i\) 不旋转。
  • \(P_i\neq i,Q_i= i\)\(q_i\) 随便取,\(p_i\) 不旋转,连边 $S\rightarrow p_i $ 表示割掉该边后 \(p_i\) 不旋转。
  • \(P_i\neq Q_i \neq i\)\(p_i\)\(q_i\) 都不得旋转,连边 \(q_i\rightarrow p_i\) 表示割掉该边后 \(p_i,q_i\) 都不旋转。
  • \(P_i=Q_i \neq i\),连边 \(q_i\rightarrow p_i\) 表示割掉该边后 \(p_i,q_i\) 都不旋转,连边 \(p_i\rightarrow q_i\) 表示割掉该边后 \(p_i,q_i\) 都旋转。

流量都是 \(1\),于是跑最小割即可,由于是二分图时间复杂度 \(O(n\sqrt n)\)

总结

  • 重要观察:排列会成环。
  • 重要观察:对于分类讨论后使用文理分科模型建图。

Code

#include<bits/stdc++.h>
#define ll long long
#define N 400005
#define endl "\n" 
#define fi first
#define se second
using namespace std;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-6;
ll n,p[N],q[N];
ll a[N],b[N];
ll cnt=0;
ll st,ed;
namespace dinic{
    struct edge{
        ll y,val,id;
    };
    vector<edge>v[N];
    queue<ll>qu;
    ll dep[N],now[N];
    bool bfs(){
        for(int i=st;i<=ed;i++)dep[i]=-1,now[i]=0;
        dep[st]=0;
        qu.push(st);
        while(!qu.empty()){
            auto t=qu.front();
            qu.pop();
            for(auto [y,val,id]:v[t]){
                if(dep[y]>=0||!val)continue;;
                dep[y]=dep[t]+1;
                qu.push(y);
            }
        }
        return dep[ed]>=0;
    }
    ll dfs(ll x,ll flow){
        if(x==ed)return flow;
        for(int i=now[x];i<v[x].size();i++){
            now[x]=i;
            auto [y,val,id]=v[x][i];
            if(dep[y]!=dep[x]+1||!val)continue;
            ll t=dfs(y,min(flow,val));
            if(t){
                v[x][i].val-=t;
                v[y][id].val+=t;
                return t;
            }else dep[y]=-1;
        }
        return 0;
    }
    ll sol(){
        ll res=0,ans=0;
        while(bfs())while(ans=dfs(st,inf))res+=ans;
        return res;
    }
    void add(ll x,ll y,ll z){
        ll sid=v[x].size();
        ll eid=v[y].size();
        v[x].push_back({y,z,eid});
        v[y].push_back({x,0,sid});
    }
}using namespace dinic;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    cin>>n;
    ll res=n;
    for(int i=1;i<=n;i++){
        cin>>p[i];
        p[i]++;
    }
    for(int i=1;i<=n;i++){
        if(a[i])continue;
        a[i]=++cnt;
        for(int j=p[i];j!=i;j=p[j])a[j]=cnt;
    }
    for(int i=1;i<=n;i++){
        cin>>q[i];
        q[i]++;
    }
    for(int i=1;i<=n;i++){
        if(b[i])continue;
        b[i]=++cnt;
        for(int j=q[i];j!=i;j=q[j])b[j]=cnt;
    }
    st=0,ed=cnt+1;
    for(int i=1;i<=n;i++){
        if(q[i]==p[i]&&p[i]==i){
            res--;
            continue;
        }
        if(q[i]==p[i]){
            add(a[i],b[i],1);
            add(b[i],a[i],1);
            continue;
        }
        if(p[i]!=i&&q[i]!=i){
            add(b[i],a[i],1);
            continue;
        }
        if(p[i]==i){
            add(b[i],ed,1);
            continue;
        }
        if(q[i]==i){
            add(st,a[i],1);
            continue;
        }
    }
    cout<<res-sol();
    return 0;
}
posted @ 2024-09-27 14:34  yshpdyt  阅读(14)  评论(0)    收藏  举报