2019.8.5 NOIP模拟测试15 反思总结

日常爆炸,考得一次比一次差XD

可能还是被身体拖慢了学习的进度吧,虽然按理来说没有影响。大家听的我也听过,大家学的我也没有缺勤多少次。

那么果然还是能力问题吗……?

虽然不愿意承认,但显然就是这样。对于多次考试来说,身体原因状态原因都是一时的理由,而肉眼可见的下滑不能用这些去掩饰。

今天还有考试,让我看看我是不是到此为止。

T1建设城市:

一眼组合数学插板法+容斥,抓起笔写了写式子,插板法没有难度,容斥就emmmm。

没写过容斥的题…也没有自己推过式子…

再看一眼数据范围看看能拿多少部分分,想到一个DP。其实会想到很正常,因为之前考过一次类似的题目,那道题的解法就有DP和容斥两种。但是数据范围不一样,这边只适合容斥。

考场上我没想起来那道题,但是很容易推出来DP,写了个搜索当对拍,码完就滚蛋了。

考完试就在摸鱼【老毛病】,然后最后十分钟盯着DP突然垂死病中惊坐起想到前缀和可以把一部分内容优化掉,然后试图码出来。当时那道题其实也有前缀和这个过程。然后再次暴露了我码力不足的问题,前缀和打炸了,40分封顶。

正解是很简单的容斥【但我没推出来】。首先是把所有情况算出来,插板法可得C(m-1,n-1)。然后减去一个城市拿多了,先把整个m减去k,之后再给这个城市强行加上,就是C(m-k-1,n-1),然后可以任选每个城市取多,所以再乘上一个C(n,1)。但是这样会减多,保证一个城市拿多,其他城市可能在分的时候也会多,例如两个城市拿多的情况可能就被重复算了好几次。于是再加上两个城市拿多的情况,C(m-2&k-1,n-1)*C(n,2)。然后一直容斥下去…边界是m-i*k-1>n-1。

预处理一下阶乘和逆元。对于n>m的情况,一定无法满足每个城市至少拿一个,判断一下输出0就好了。我忘了这个…差点以为阶乘逆元要处理到109

#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,k;
const long long mod=998244353;
long long rec[20000010],inv[20000010],ans;
long long ks(long long x,long long k){
    long long num=1;
    while(k){
        if(k&1){
            num=num*x%mod;
        }
        x=x*x%mod;
        k>>=1;
    }
    return num;
}
long long C(int n,int m){
    return rec[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&k);
    if(n>m){
        printf("0\n");
        return 0;
    }
    rec[0]=inv[0]=rec[1]=1;
    for(int i=2;i<=m;i++){
        rec[i]=rec[i-1]*i%mod;
    }
    inv[m]=ks(rec[m],mod-2);
    for(int i=m-1;i>=1;i--){
        inv[i]=inv[i+1]*(i+1)%mod;
    }
    ans=C(m-1,n-1);
    for(int i=1;m-i*k>=n&&i<=n;i++){
        if(i&1)ans=(ans-(C(m-i*k-1,n-1)*C(n,i)%mod)+mod)%mod;
        else ans=(ans+(C(m-i*k-1,n-1)*C(n,i)%mod)%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

不要摸鱼,不要摸鱼,不要摸鱼!提醒今天的我也提醒未来的我以及所有能看到的人。不要太早对自己丧失信心…不要放弃思考。

要对自己有信心啊墨雨笙!!!【啊这话说出来自己都觉得无力】

T2轰炸行动:

这是一道语文神题,至少一半的人都看错了题。限制是连通性而不是相邻边。

而我就更睿智了,我是错误看题的错解,我二分图染色…

实际上就按错的理解,也不可能是二分图染色。只要完全图就必爆炸。完全没想到呢我大约五行缺脑?

正解是tarjan板子。首先对于一条链上的点,一定要一个一个炸,所以最优解一定大于等于最长链的长度。然后对于其它短链,都可以和最长链平行操作。所以答案就是最长链长度。

scc缩点记一个tarjan,然后拓扑记最大可能链长,输出就好了。比较的时候是f[y]与f[x]+siz[y]比较,因为f[y]可能已经被别的入边传来的答案更新过了,而siz[y]才是一开始的初值。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,m,ans,f[2000010];
int ver[2000010],Next[2000010],head[2000010],tot,tim,vis[2000010];
int dfn[2000010],low[2000010],cnt,c[2000010],siz[2000010],stack[2000010],st;
int du[2000010],ver1[2000010],Next1[2000010],head1[2000010],tot1;
queue<int>q;
void add(int x,int y){
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot; 
}
void add1(int x,int y){
    ver1[++tot1]=y;
    Next1[tot1]=head1[x];
    head1[x]=tot1; 
}
void tarjan(int x){
    low[x]=dfn[x]=++tim;
    stack[++st]=x;
    vis[x]=1;
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]){
        int p;
        cnt++;
        do{
            p=stack[st--];
            vis[p]=0;
            c[p]=cnt;
            siz[cnt]++;
        }while(p!=x);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    } 
    for(int i=1;i<=n;i++){
        for(int j=head[i];j;j=Next[j]){
            int y=ver[j];
            if(c[i]!=c[y]){
                add1(c[i],c[y]);
                du[c[y]]++;
            }
        }
    }
    for(int i=1;i<=cnt;i++){
        if(!du[i]){
            q.push(i);
            ans=max(ans,siz[i]);
        }
        f[i]=siz[i];
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head1[u];i;i=Next1[i]){
            int y=ver1[i];
            f[y]=max(f[y],f[u]+siz[y]);
            ans=max(ans,f[y]);
            du[y]--;
            if(!du[y])q.push(y);
        }
    }
    printf("%d",ans);
    return 0;
}
View Code

仔细审题至少三遍!第三题的坑点都看出来了,第二题死得这么惨烈……

T3石头剪刀布:

这个之后好好写一下,现在没时间了,先丢代码。

#include<iostream>
#include<cstdio>
using namespace std;
int n;
double a[110],b[110],c[110],tol[110][5],f[55][55][55][55],g[55][55][55][55],ans;
double C[110][110];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf",&a[i],&c[i],&b[i]);
        tol[i][1]=a[i]/300.0;
        tol[i][2]=b[i]/300.0;
        tol[i][3]=c[i]/300.0;
    }
    for(int i=0;i<=100;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++){
            C[i][j]=C[i-1][j-1]+C[i-1][j];
        }
    }
    g[0][0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=i;j>=0;j--){
            for(int k=i-j;k>=0;k--){
                for(int l=i-j-k;l>=0;l--){
                    g[i][j][k][l]=g[i-1][j][k][l];
                    if(j)g[i][j][k][l]+=g[i-1][j-1][k][l]*tol[i][1];
                    if(k)g[i][j][k][l]+=g[i-1][j][k-1][l]*tol[i][2];
                    if(l)g[i][j][k][l]+=g[i-1][j][k][l-1]*tol[i][3];
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j>=0;j--){
            for(int k=i-j;k>=0;k--){
                for(int l=i-j-k;l>=0;l--){
                    if(j){
                        f[j][k][l][1]+=f[j-1][k][l][1]*tol[i][1];
                        f[j][k][l][2]+=f[j-1][k][l][2]*tol[i][1];
                        f[j][k][l][3]+=f[j-1][k][l][3]*tol[i][1];
                    }
                    if(k){
                        f[j][k][l][1]+=f[j][k-1][l][1]*tol[i][2];
                        f[j][k][l][2]+=f[j][k-1][l][2]*tol[i][2];
                        f[j][k][l][3]+=f[j][k-1][l][3]*tol[i][2];
                    }
                    if(l){
                        f[j][k][l][1]+=f[j][k][l-1][1]*tol[i][3];
                        f[j][k][l][2]+=f[j][k][l-1][2]*tol[i][3];
                        f[j][k][l][3]+=f[j][k][l-1][3]*tol[i][3];
                    }
                    f[j][k][l][1]+=g[i-1][j][k][l]*tol[i][1];
                    f[j][k][l][2]+=g[i-1][j][k][l]*tol[i][2];
                    f[j][k][l][3]+=g[i-1][j][k][l]*tol[i][3];
                }
            }
        }
    }
    for(int j=0;j<n;j++){
        for(int k=0;k+j<n;k++){
            for(int l=0;l+k+j<n;l++){
                ans+=max(f[j][k][l][1]+f[j][k][l][2]*3,max(f[j][k][l][2]+f[j][k][l][3]*3,f[j][k][l][3]+f[j][k][l][1]*3))/(C[n][j+k+l]*(n-j-k-l));
            }
        }
    }
    printf("%.12lf",ans);
    return 0;
} 
View Code

所以又是日常爆炸的一次考试,暴露问题很多,但是有种这就是我的极限的感觉。

很差,我很糟糕,没什么好说的。

今天的考试…祝诸位和自己RP++,并且希望自己不要放弃…

猜你喜欢

转载自www.cnblogs.com/chloris/p/11330380.html