2019-8-9 考试总结

A. 建设城市

很熟悉的题面,和"那一天我们许下约定"差不多。

$n^2$暴力很好想,$70$分也很好拿。

但是没拿到。。

正解是个容斥。

用总的方案数减去不合法的方案数。

不合法的也就是建设队大于等于$k+1$的。

然后就容斥。

$ans=C_{m-1}^{n-1}-\sum \limits_{i=1}^{m-ik-1>=0} (-1)^iC_n^i\times C_{m-ik-1}^{n-1}$。

左边那个式子是个挡板,不考虑$k$的限制,每个城市至少有$1$的方案数。

右边是个容斥,表示至少$i$个城市不合法的方案数。

从$m$个建设队中选出$ik$个给$i$个城市,然后每个城市再分$1$,最后的那些随便分。

在用一个挡板法。

所以最后$C$的底数是$m-ik-n+n-1$,也就是$m-ik-1$。

然后再乘一个$C_n^i$。

就是这个式子。

丑陋的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define Maxn 10000050
#define Reg register
#define mod 998244353
#define int long long
#define _max(x,y) ((x)>(y)?(x):(y))
#define C(x,y) (((x)<(y))?0:(fac[x]*inv[y]%mod*inv[(x)-(y)]%mod))
using namespace std;
int n,m,k,fac[Maxn],inv[Maxn],lss[Maxn];
signed main()
{
    scanf("%lld%lld%lld",&n,&m,&k);
    fac[0]=inv[0]=fac[1]=inv[1]=lss[1]=1;
    if(n>m) printf("0");
    else
    {
        for(Reg int i=2;i<=m;++i)
        {
            fac[i]=fac[i-1]*i%mod;
            lss[i]=(mod-mod/i)*lss[mod%i]%mod;
            inv[i]=inv[i-1]*lss[i]%mod;
        }
        int ans=C(m-1,n-1);
        for(Reg int i=1,cur;i<=n;++i)
        {
            if(m-i*k-1<0) break;
            cur=(i&1)?-1:1;
            ans=(ans+cur*C(n,i)%mod*C(m-i*k-1,n-1)%mod+mod)%mod;
        }
        printf("%lld",(ans+mod)%mod);
    }
    return 0;
}
View Code

 

B. 轰炸行动

正解:

$Tarjan$缩$scc$,然后跑拓扑找最长链。

好吧,当时想到了$Tarjan$和拓扑,

没想到要找最长链。。

这个题只要找最长链的节点个数就可以了。

因为每一条链上的点都要一个一个炸。

丑陋的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#define Maxn 10000050
#define Reg register
#define int long long
#define _min(x,y) ((x)<(y)?(x):(y))
#define _max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,m,tot=0,top=0,fir[Maxn],fic[Maxn];
int cnt,indx,low[Maxn],dfn[Maxn],stack[Maxn],ins[Maxn],bel[Maxn],sum[Maxn];
int du[Maxn],dep[Maxn];
struct Tu {int st,ed,next;} lian[Maxn],liap[Maxn];
void add(int x,int y)
{
    lian[++tot].st=x;
    lian[tot].ed=y;
    lian[tot].next=fir[x];
    fir[x]=tot;
    return;
}
void adp(int x,int y)
{
    liap[++top].st=x;
    liap[top].ed=y;
    liap[top].next=fic[x];
    fic[x]=top;
    ++du[y];
    return;
}
void tarjan(int x)
{
    low[x]=dfn[x]=++indx;
    stack[++stack[0]]=x; ins[x]=1;
    for(Reg int i=fir[x];i;i=lian[i].next)
    {
        if(!dfn[lian[i].ed])
        {
            tarjan(lian[i].ed);
            low[x]=_min(low[x],low[lian[i].ed]);
        }
        else if(ins[lian[i].ed])
            low[x]=_min(low[x],dfn[lian[i].ed]);
    }
    if(low[x]==dfn[x])
    {
        ++cnt;
        while(stack[stack[0]]!=x)
        {
            bel[stack[stack[0]]]=cnt;
            ins[stack[stack[0]--]]=0;
        }
        bel[stack[stack[0]]]=cnt;
        ins[stack[stack[0]--]]=0;
    }
    return;
}
void topsort()
{
    queue<int> q; int p=1;
    for(Reg int i=1;i<=cnt;++i)
    {
        if(!du[i])
        {
            q.push(i); dep[i]=sum[i];
            p=_max(p,dep[i]);
        }
    }
    while(!q.empty())
    {
        int x=q.front(); q.pop();
//        cout<<x<<' '<<sum[x]<<' '<<dep[x]<<endl;
        p=_max(p,dep[x]);
        for(Reg int i=fic[x];i;i=liap[i].next)
        {
            --du[liap[i].ed];
            dep[liap[i].ed]=_max(dep[liap[i].ed],dep[x]+sum[liap[i].ed]);
            if(du[liap[i].ed]==0)
            {
                q.push(liap[i].ed);
            }
        }
    }
    printf("%lld",p);
    return;
}
signed main()
{
//    freopen("text.in","r",stdin);
    indx=cnt=tot=top=0;
    scanf("%lld%lld",&n,&m);
    for(Reg int i=1,x,y;i<=m;++i)
    {
        scanf("%lld%lld",&x,&y);
        add(x,y);
    }
    for(Reg int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    for(Reg int i=1;i<=n;++i)
    {
        ++sum[bel[i]];
//        cout<<bel[i]<<' ';
    }
//    cout<<endl;
    for(Reg int i=1;i<=tot;++i)
        if(bel[lian[i].st]!=bel[lian[i].ed])
            adp(bel[lian[i].st],bel[lian[i].ed]);
    topsort();
    return 0;
}
View Code

 

C. 石头剪刀布

挺难的,我不会。

 

总结:

看到$T1$基本上是原题,而且我又什么都想不起来,心态近乎爆炸。

最后连$n^2$暴力的分都没拿到。

说是低错,就是没水平。。。

$T2$用$Tarjan$缩$scc$很好想。

拓扑排序找最长链这比较难想。

考试一碰见图论和方案计数$dp$和概率期望就死了。

$T3$用玄学$dfs$和特判水到$20$分。

$T1$和$T2$就惨了。

最后$20+0+20=40$。

没什么水平。。。

posted @ 2019-08-09 15:25  Milk_Feng  阅读(140)  评论(0编辑  收藏  举报