zoukankan      html  css  js  c++  java
  • 【考试反思】联赛模拟测试16

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

    T1: 30 ( ightarrow) 0

    T3: 20 ( ightarrow) 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 ",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
    ",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
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Ansible概述
    iptables端口转发
    iptables配置实例
    iptables常用操作
    iptables常用命令
    每日总结3.15
    每日总结3.12
    每日总结3.11
    每日总结3.10
    每日总结3.9
  • 原文地址:https://www.cnblogs.com/Midoria7/p/13815068.html
Copyright © 2011-2022 走看看