zoukankan      html  css  js  c++  java
  • 模拟测试.20190809

    一次比一次差是要闹哪样啊,次次都看错题什么状态啊,下次是不是就爆零了啊......

    可能是最近知识学得太快了吧,什么都来不及深究就马上考试or进入下一个专题,做题也仅限于学长讲过的(没讲过的直接死亡(某数位dp))

    集训还有10天,不知不觉过去这么长时间了,我承认最近确实有点浮躁,做题总是静不下心

    再这样可能真的要退役了吧(笑),可是我不想啊

    所以接下来努力吧,尽管努力并不一定有回报,但不尝试又怎么知道结果呢

    以上

    T1:建设城市(city)

    和之前一道考试题很像啊......但是数据强了很多,然而我还是只会打n^2暴力,加上特判总共获(pian)得(dao)了70pts

    正解很明显的容斥啊......考试时候总想着需要枚举每个人而不敢打容斥(其实对每个人的枚举合并就能得到一个非常简单的柿子了)

    考完才发现对每个人的枚举是一样的,也就是说只需要枚举重合的人就好了

    全集是c(m-1,n-1),容斥掉有超过k的,枚举超过的天数,对于天数i,超过i天的方案即为C(n,i)*C(m-i*k-1,n-1)(把)

    容斥一发,奇减偶加就好了

    #include<bits/stdc++.h>
    #define int long long
    #define cri const register int
    #define re register
    using namespace std;
    const int mod=998244353;
    int jie[10000010],ni[10000010];
    inline int c(cri x,cri y){
        if(x<y||x<0||y<0) return 0;
        return 1ll*jie[x]*ni[y]%mod*ni[x-y]%mod;
    }
    inline int qpow(int a,int b){
        int ans=1;
        for(;b;b>>=1,a=1ll*a*a%mod)
            if(b&1) ans=1ll*ans*a%mod;
        return ans;
    } 
    signed main(){
        int n,m,k,ans;
        scanf("%lld%lld%lld",&n,&m,&k);
        if(n>m||m>1ll*n*k){
            puts("0");
            return 0;
        }
        jie[0]=1;
        for(int i=1;i<=m;i++) jie[i]=1ll*jie[i-1]*i%mod;
        ni[m]=qpow(jie[m],mod-2);
        for(int i=m;i>=1;i--) ni[i-1]=1ll*ni[i]*i%mod;
        ans=c(m-1,n-1);
        //cout<<ans<<endl;
        for(int i=1,j=-1;i<=m;i++,j=-j)
            ans=(ans+1ll*j*c(n,i)*c(m-i*k-1,n-1)%mod+mod)%mod;
        printf("%lld",ans);
    }
    View Code

    T2:轰炸行动(bomb)

    全场最水,然而半个机房由于看错题喜提10分的好成绩

    仔细看题我们发现在一条链上的两两都不能同时轰炸,一个强联通分量上的同理

    然后我们建图,tarjan,拓扑就好了

    #include<bits/stdc++.h>
    #define ll long long
    #define cri const register int
    #define re register
    using namespace std;
    int num,cnt,dcc,fa[1000010],to[2000010],la[2000010],bl[1000010];
    int dfn[1000010],low[1000010],sta[1000010],top,size[1000010],fr[1000010];
    inline void add(cri x,cri y){
        to[++cnt]=y;
        fr[cnt]=x;
        la[cnt]=fa[x];
        fa[x]=cnt;
    }
    int tos[1000010],las[1000010],cnts,du[1000010],dp[1000010],v[1000010];
    inline void adds(cri x,cri y){
        tos[++cnts]=y;
        las[cnts]=fa[x];
        fa[x]=cnts;
    }
    void tarjan(cri x){
        dfn[x]=low[x]=++num;
        sta[++top]=x;v[x]=1;
        for(int i=fa[x];i;i=la[i])
            if(!dfn[to[i]]){
                tarjan(to[i]);
                low[x]=min(low[to[i]],low[x]);
            }
            else if(v[to[i]])low[x]=min(low[x],dfn[to[i]]);
        if(low[x]==dfn[x]){
            int y;dcc++;
            do{
                y=sta[top--];
                bl[y]=dcc;
                size[dcc]++;
                v[y]=0;
            }while(y!=x);
            //puts("");
        }
    }
    signed main(){
        int n,m,x,y,ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        memset(fa,0,sizeof fa);
        for(int i=1;i<=cnt;i++)
            if(bl[to[i]]!=bl[fr[i]]) adds(bl[fr[i]],bl[to[i]]),du[bl[to[i]]]++;
        queue<int>q;
        for(int i=1;i<=dcc;i++)
            if(!du[i]) q.push(i);
        while(!q.empty()){
            x=q.front();q.pop();
            dp[x]+=size[x];
            ans=max(ans,dp[x]);
            for(int i=fa[x];i;i=las[i]){
                du[tos[i]]--;
                dp[tos[i]]=max(dp[tos[i]],dp[x]);
                if(!du[tos[i]]) q.push(tos[i]);
            }
        }
        printf("%d",ans);
    }
    View Code

    T3:石头剪刀布(rps)

    神dp,考场上一度以为是np完全不可做(现在我也这么认为),打了骗分想骗20然而只弄到10分

    由于我们根本无法完全分析出最优决策,模拟or考虑顺序绝对吃屎

    我们思考有没有方法可以不考虑对手的顺序,于是我们得到了这样的dp定义:dp[i][j][k][now]表示出现了i个石头,j个剪刀,k个布,下一次出now的概率

    等等怎么想到的?发生了什么?(反正我想不到啊喂)

    但dp数组显然无法直接转移,我们考虑辅助数组g[i][j][k],表示出现了i个石头,j个剪刀,k个布的概率

    显然有g[i][j][k]+=g[i-1][j][k]*r[t]+g[i][j-1][k]*s[t]+g[i][j][k-1]*p[t]

    f数组也有相似转移,即

    f[i][j][k][l]+=f[i-1][j][k][l]*r[t]+f[i][j-1][k][l]*s[t]+f[i][j][k-1]*p[t]+g[i][j][k]*(r[t]+s[t]+p[t])

    复杂度O(n^4)

    #include<bits/stdc++.h>
    #define ll long long
    #define cri const register int
    #define crs const register short
    #define re register
    using namespace std;
    int n;
    long double ans,f[55][55][55][5],sjb[4][55],c[55][55];
    signed main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%Lf%Lf%Lf",&sjb[1][i],&sjb[3][i],&sjb[2][i]);
            for(int j=1;j<=3;j++) sjb[j][i]/=300;
        }
        c[0][0]=1;
        for(int i=1;i<=n;i++){
            c[i][0]=1;
            for(int j=1;j<=i;j++)
                c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
        f[0][0][0][0]=1;
        for(int t=1;t<=n;t++)
            for(int i=t;i>=0;i--)
                for(int j=t-i;j>=0;j--)
                    for(int k=t-i-j;k>=0;k--)
                        for(int now=(t==i+j+k?0:3);now>=0;now--){
                            f[i][j][k][now]+=(i?f[i-1][j][k][now]:0)*sjb[1][t]+(j?f[i][j-1][k][now]:0)*sjb[2][t]+(k?f[i][j][k-1][now]:0)*sjb[3][t];
                            if(now) f[i][j][k][now]+=f[i][j][k][0]*sjb[now][t];
                        }
        for(int i=0;i<n;i++)
            for(int j=0;j+i<n;j++)
                for(int k=0;i+j+k<n;k++)
                    ans+=max(f[i][j][k][1]+f[i][j][k][2]*3,max(f[i][j][k][2]+f[i][j][k][3]*3,f[i][j][k][3]+f[i][j][k][1]*3))/(c[n][i+j+k]*c[n-i-j-k][1]);
        printf("%.15Lf",ans);
    }
    View Code
  • 相关阅读:
    HDU 2586 How far away?
    UVAlive 5796 Hedge Mazes
    HDU 4975 A simple Gaussian elimination problem.
    Poj 1149 PIGS
    HDU 3416 Marriage Match IV
    HDU 4912 Paths on the tree
    HDU 3277 Marriage Match III
    終於記起了帳號密碼
    codeforces194a
    codeforces195c
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11328621.html
Copyright © 2011-2022 走看看