zoukankan      html  css  js  c++  java
  • ZJOI2012 波浪))))))))))))))))))))))))))))))))))))))

    题链

    一道很良心的省选题。

    我们先考虑如何优雅的骗分。

    有30%的程序精度要求K<=3,这个时候我们只要把题目给你的那个程序拿下来改一改就好了。

    RP不差的话有30分。

    我们再观察一波数据,发现N<=10时我们可以暴力枚举所有可能,除以N!求概率。

    来一发50分代码(为了稳健,没播种子)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define SIZ 5000000
    #define abs(t) (t)>0?(t):-(t)
    using namespace std;
    int a[107],gg[11],p[11],usd[11],tot,ot;
    int n,s,t,m,GG,k,anss,ans;
    void dfs(int x){
        if (x==n+1) {if (anss>=m) ans++; return;}
        for (int i=1;i<=n;i++)
         if (!usd[i]) {
             usd[i]=1; p[x]=i; anss+=abs(i-p[x-1]); dfs(x+1); 
            anss-=abs(i-p[x-1]); usd[i]=0;
         }
    }
    void out(long double xx,int g){
        if (g==-1) {
            printf("%d",(int)xx); return;
        }
        printf("%d.",(int)xx); xx=xx*10;
        while (g--) {
           printf("%d",(int)xx); xx=xx*10-((int)xx)*10;
        }
        xx=xx*10; GG=(int)xx; if (GG%10<4) GG=GG/10; else GG=GG/10+1;
        printf("%d",GG); 
    }
    void Out(int x,int y,int g){
        if (g==-1) {
            if (x*2>=y) printf("1
    ");
            else printf("0
    "); return;
        }
        printf("%d.",x/y); x=x%y*10;
        while (g--) {
            printf("%d",x/y); x=x%y*10;
        }
        GG=x/y; ot=x%y; if (ot*2>=y) GG++;
        printf("%d",GG);
    }
    int main () {
        scanf("%d%d%d",&n,&m,&k);
        if (n<=10){
            for (int i=1;i<=n;i++) {
                anss=0; p[1]=i; usd[i]=1; dfs(2); usd[i]=0;
            }
             tot=1;
            for (int i=1;i<=n;i++) tot=tot*i;
            Out(ans,tot,k-1); 
            return 0;
        }
        for (int i=1;i<n;i++) a[i]=i;
        s=0;
        for (int i=0; i<SIZ; i++) {
            random_shuffle(a,a+n); t=0;
            for (int j=0; j<n-1; j++) t+=abs(a[j+1]-a[j]);
            if (t>=m) s++;
        }
        long double XX=s/(1.0*SIZ);
        out(XX,k-1);
    }
    View Code

    其实第二个暴力给我们了一种接近标算的思路。

    我们只要快速求出比M大的有几种。

    那么我们考虑DP:

    绝对值不好搞,那么我们按大小从小到大依次插入。

    那么插入一个数有很多种情况。

    1.插入以后它两边都没有数。

    2.插入以后它两边都有数。

    3.插入以后它的一边有数。

    4.插入在边界上,且它旁边没有数。

    5.插入在边界上,且它旁边有数。

    55种情况对应55个不同的转移,于是我们可以设一个状态来表示这些转移。

    f[i][j][k][l表示插入i个数,当前序列波动值为j,序列现在被分为k个连续的段,序列边界的状态为ll为0表示边界没有数,为1表示边界有一个数,为2表示边界有两个数。

    那么我们可以分几种情况转移,就好了。

    __float128可以替代高精度。

    #include<bits/stdc++.h>
    #define M 4500
    using namespace std;
    int n,m,k;
    namespace db{ double f[2][9001][101][3]; }
    namespace f128{ __float128 f[2][9001][101][3]; }
    template<class T>
    inline void pout(T ans,int k){
        printf("%d.",(int)ans);
        while (k--) {
            ans=(ans-(int)ans)*10;
            if(!k) ans+=0.5;
            printf("%d",(int)ans);
        }
    }
    template<class T>
    void solve(T f[][9001][101][3]){ T A;
        f[1][M-2][1][0]=1;f[1][M-1][1][1]=2;f[0][M][1][2]=1;
        for (int i=2,cur=0,pre=1;i<=n;i++,cur=pre,pre^=1) {
            memset(f[cur],0,sizeof f[cur]);
            for (int j=2*M;~j;j--) 
             for (int k=n-1;k;k--)
              for (int l=2;~l;l--) {
                  if (!(A=f[pre][j][k][l])) continue;
                  if (j+2*i<=2*M) f[cur][j+2*i][k-1][l]+=A*(k-1);
                  if (j>=2*i) f[cur][j-2*i][k+1][l]+=A*(k+1-l);
                  f[cur][j][k][l]+=A*(k*2-l);
                  if (l<2) {
                      if (j+i<=2*M) f[cur][j+i][k][l+1]+=(2-l)*A;
                      if (j>=i) f[cur][j-i][k+1][l+1]+=A*(2-l);
                  }
              }
        }
        T ans=0;for (int i=M+m;i<=2*M;i++) ans+=f[n&1][i][1][2];
        for (int i=2;i<=n;i++) ans/=i; 
        pout(ans,k);
    }
    int main () {
        scanf("%d %d %d",&n,&m,&k);
        if (k<=8) solve(db::f);
        else solve(f128::f);
    }
  • 相关阅读:
    Java基础——数组复习
    JavaScript 笔记总结
    HTML总结
    css代码添加背景图片常用代码
    Java 并发包之线程池综述
    Java 并发之Concurrent 包综述
    AQS 框架之 Lock 接口
    AQS 框架之 LockSupport 线程阻塞工具类
    JAVA 锁之 Synchronied
    ThreadLocal 线程本地变量
  • 原文地址:https://www.cnblogs.com/rrsb/p/8370521.html
Copyright © 2011-2022 走看看