【考试反思】联赛模拟测试16

草 由于今天的排名很 \(fake\),所以就不粘了

T1: 30 \(\rightarrow\) 0

T3: 20 \(\rightarrow\) 100

好多计数题啊 打快读打的最少的一场

T1:阴阳

神仙恶心人的 DP

T2:简单的序列

令左括号为 \(1\),右括号为 \(-1\)。刚学栈的时候我们就知道要求括号序列的前缀和恒大于等于 \(0\),且最后为 \(0\)

预处理 \(f[i][j]\) 表示 \(i\) 个括号和为 \(j\) 的方案数。

设最后 \(p\) 序列的方案数为 \(f[i][j]\),给出的序列的值为 \(res\),那么 \(q\) 序列的方案就应该是 \(f[n-m-i][-j-res]\),但下标不能为负,但我们发现 \(f[n-m-i][-j-res]\)\(f[n-m-i][j+res]\) 是相等的(左右括号互换而已)。直接乘积加上。

注意要求括号序列时时合法,有一些恶心的边界要判。其中重要的就是要记录计算原有序列的最小前缀值,从而确定 \(p\) 序列左括号的下界。

T3:简单的期望

如题,简单的期望。只需 printf("%lf\n",0.0/0.0) 即可。

同样是神仙 DP。可以发现,最多进行 200 次加法,所以大于八位的进位只会进行一次。所以设 \(f[i][j][k][0/1]\) 表示操作前 \(i\) 次,最后 8 位状态是 \(j\),从第 9 位开始有连续 \(k\) 位相同,第 9 位为 \(0/1\) 的概率。

直接看代码吧。

Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=300+10;
const int base=(1<<8)-1;
int x,n,p;
int bit[maxn];
long double pmul,padd,ans;
long double f[maxn][maxn][maxn][2];
//操作前i次 最后8位状态是j 从第9位开始有连续k位相同 第9位为0/1的概率

int main(){
#ifndef LOCAL
    freopen("exp.in","r",stdin);
    freopen("exp.out","w",stdout);
#endif
    scanf("%d%d%d",&x,&n,&p);
    pmul=1.0*p/100;padd=1.0*(100-p)/100;
    int temp=x>>8,flag=temp&1,cnt=0;
    if(temp==0)cnt=1;
    else while((temp&1)==flag){
        cnt++;temp>>=1;
    }
    f[0][x&base][cnt][flag]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=base;j++)
            for(int k=1;k<=base;k++){
                f[i][j+1][k][0]+=f[i-1][j][k][0]*padd;
                f[i][j+1][k][1]+=f[i-1][j][k][1]*padd;//直接加 不进位
            }
        for(int k=1;k<=base;k++){
            f[i][0][k][0]+=f[i-1][base][k][1]*padd;//加 超级进位
            f[i][0][1][1]+=f[i-1][base][k][0]*padd;//加 进一位
        }
        for(int j=0;j<=base/2;j++)//j最高位是0
            for(int k=1;k<=base;k++){
                f[i][j<<1][1][0]+=f[i-1][j][k][1]*pmul;//乘 第9位为1
                f[i][j<<1][k+1][0]+=f[i-1][j][k][0]*pmul;//乘 第9位为0
            }
        for(int j=base/2+1;j<=base;j++)//j最高位是1
            for(int k=1;k<=base;k++){
                f[i][j<<1&base][1][1]+=f[i-1][j][k][0]*pmul;//乘 第9位为0
                f[i][j<<1&base][k+1][1]+=f[i-1][j][k][1]*pmul;//乘 第9位为1
            }
    }
    for(int i=1;i<=base;i++){
        int now=i;
        while((now&1)==0){
            now>>=1;bit[i]++;
        }
    }
    for(int j=1;j<=base;j++)
        for(int k=1;k<=base;k++){
            ans+=1.0*(f[n][j][k][0]+f[n][j][k][1])*bit[j];
        }
    for(int k=1;k<=base;k++)
        ans+=1.0*f[n][0][k][0]*(k+8)+1.0*f[n][0][k][1]*8;
    printf("%.10Lf\n",ans);
    return 0;
}

T4:简单的操作

首先,考场上看错题了,没看到合并的两点不能直接相连。

那么,首先存在奇环的情况一定无解,因为他最终会缩成一个三元环,然后就 GG 了。判奇环的方法是黑白染色,详情可以看老姚博客

如果是一棵树,最优的情况一定是合并成一条直径。那么对于一个普通的联通块来说呢?直径就是两点之间最短路的最大值。所以答案就是所有联通块的最短路的最大值的和。

由于是无权图,所以用 bfs 即可 \(O(nm)\) 求解。

Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
const int maxm=1e5+10;
int n,m;
long long ans;
int len[maxn];

struct Edge{
    int from,to,nxt;
}e[maxm<<1];

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int head[maxn],cnt;
inline void add(int u,int v){
    e[++cnt].from=u;
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}

int tot;
int col[maxn],belong[maxn];
void dfs(int u,int now){
    belong[u]=now;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!col[v]){
            col[v]=-col[u];dfs(v,now);
        }else if(col[u]==col[v]){
            puts("-1");exit(0);
        }
    }
}

int Time;
int dis[maxn],vis[maxn];
int bfs(int s){
    int res=0;
    queue<int> q;
    q.push(s);dis[s]=0;vis[s]=Time;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(vis[v]==Time)continue;
            vis[v]=Time;q.push(v);
            dis[v]=dis[u]+1;
            res=max(res,dis[v]);
        }
    }
    return res;
}

int main(){
#ifndef LOCAL
    freopen("merge.in","r",stdin);
    freopen("merge.out","w",stdout);
#endif
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v);add(v,u);
    }
    for(int i=1;i<=n;i++)
        if(!col[i]){
            col[i]=1;dfs(i,++tot);
        }
    for(int i=1;i<=n;i++){
        Time++;
        len[belong[i]]=max(len[belong[i]],bfs(i));
    }
    for(int i=1;i<=tot;i++)
        ans+=len[i];
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-10-14 15:17  Midoria7  阅读(107)  评论(0编辑  收藏  举报