看见机房有大佬上周写了上面的普及信心赛 于是我康了康 8月的提高组模拟赛 9月的还没开始qwq

真的 有点难 主要是我先打开了T2 我再次 对自己的数学产生了怀疑 我现在还是不会写T2

T1 又又又又都错题了 下次重建图 尽量写vector 都写 邻接表 变量差不多的容易搞混 我这个同学变又写错了 

T1 :https://nanti.jisuanke.com/t/41086

题目大意就是 一个有向图 删一个点 把与他直接和间接 相连的点 删掉 然后 求删掉所有点的最小最大代价 ;

为了避免这个环的情况 我们显然是先 tarjan 求一下强连通分量 然后考虑 缩点 显然是删掉这个强连通分量的任意一个点 这个强连通分量都会被删掉 

但是题目要求我们求出最大最小代价 那我们在求tarjan的过程中 维护每一个块的最大最小代价

那么对于最小代价 显然是缩点之后入度为0的节点的代价的累和 

对于最大代价 我们反向建图 从叶子结点往上便利 然后每一个连通块的最大代价 累和 即可

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
template<typename T>inline void read(T &x) {
    x=0;T f=1,ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    if(ch=='-') f=-1, ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
const int N=250000;
int n,m,x,y,cnt=0,ans1,ans2,num,tot,tc,top;
int in1[N],in2[N],Stack[N],minn[N],cost[N],maxx[N],dfn[N],low[N],lin[N],linc[N],ins[N],belong[N];
struct gg {
    int y,next;
}a[N],e[N];
inline void add(int x,int y) {
    a[++tot].y=y;
    a[tot].next=lin[x];
    lin[x]=tot;
}
inline void add_c2(int x,int y) {
    e[++tc].y=y;
    e[tc].next=linc[x];
    linc[x]=tc;
}
inline void tarjan(int x) {
    dfn[x]=low[x]=++num;
    Stack[++top]=x; ins[x]=1;
    for(int i=lin[x];i;i=a[i].next) {
        int y=a[i].y;
        if(!dfn[y]) {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(ins[y])
            low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x]) {
        ++cnt;
        int k;
        do {
            k=Stack[top--];
            ins[k]=0;
            belong[k]=cnt;
            minn[cnt]=min(minn[cnt],cost[k]);
            maxx[cnt]=max(maxx[cnt],cost[k]);
        }while(x!=k);
    }
}
inline void topsort() {
    queue<int>q;
    for(int i=1;i<=cnt;i++) if(!in2[i]) q.push(i);
    while(q.size()) {
        int x=q.front();ans2+=maxx[x]; q.pop();
        for(int i=linc[x];i;i=e[i].next) {
            int y=e[i].y;
            in2[y]--;
            if(!in2[y]) q.push(y);
        }
    }
}
int main() {
    //freopen("1.in.cpp","r",stdin);
    read(n); read(m);
    for(int i=1;i<=n;i++) read(cost[i]),minn[i]=inf,maxx[i]=-inf;
    for(int i=1;i<=m;i++) {
        read(x); read(y);
        add(x,y);
    }
    for(int i=1;i<=n;i++) {
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=n;i++) {
        //cout<<maxx[i]<<endl;
        for(int j=lin[i];j;j=a[j].next) {
            int y=a[j].y;
            if(belong[i]!=belong[y]) {
                //add_c(belong[i],belong[y]);没必要建图了; 
                add_c2(belong[y],belong[i]);
                in1[belong[y]]++;
                in2[belong[i]]++;
            }
        }
    }
    ans1=ans2=0;
    for(int i=1;i<=cnt;i++)
        if(!in1[i]) ans1+=minn[i];
    topsort();
    printf("%d %d\n",ans1,ans2);
    return 0;
} 

T2 恶心数学题??? 原来只做过一个简化版的qwq 模拟赛当时考了 然后暴毙了;

那个模拟赛 我也没有写题解 那我在这里总结一下好吧 题目大意:

从(0,0)这个点 不跨过 y=x 和 y=x-(n-m) 到达(n,m)的方案数 保证 n>=2m

显然需要用不考虑跨过任何一条直线的方案数-跨过某一条直线的方案数*2+跨过两条的方案数;

这种题目的一般思路显然是 总的方案数 $\tbinom{n+m}{m}$

然后考虑 跨过某一条直线的方案数 $\tbinom{n+m}{m-1}$

因为题目保证n>=2m 所以跨过第二条直线的时候 就没有机会跨过第一个了qwq 所以一定是 先跨过第一条线 在跨过第二条线

用和卡特兰数类似的方法也能求出来 方案数 $\tbinom{n+m}{m}$-$\tbinom{n+m}{m-1}$*2+$\tbinom{n+m}{m-2}$


这个T2 就比较恶心了 目标就是求从 (0,0)走到 (n,m)  且不经过 y=x+a 和 y=x+b 这两条的方案数,模数为 998244353 。

考虑 怎么做呢 其实 我的思路也是在不断 订正的 我第一遍看到 不会写 只会分类讨论 但是 刘神 指导说 应该是有通解的 

那么我们不妨一点一点思考 讨论一下 这种组合数求解 这种问题的方法 


如果 给定 (n,m) 和一个点 p(a,b) 只能往右 往上走 求出 不经过这个点p 到达终点 的方案数;

那么我们也是用所有的方案数 减去 经过 p的 方案数 

总的方案数 $\tbinom{n+m}{m}$ 然后考虑 一定经过p的方案数 那么我们先从(0,0) 走到 (a,b) 的方案数 

01-22 11:11