zoukankan      html  css  js  c++  java
  • 赤壁情:dp

    首先这道题用到的3个新关键字大概讲一下:

    (我刚学会仅仅会瞎搞做题,欢迎大神补充)

    static:声明一个变量并清空。(不知道用不用时间,求解答)

    具体用法:static 变量类型 变量名。如:static int a[1005];

    百度了一下。static在第一次声明时是0,但是下次进入这个函数时它不会再次清空而是保持原状。

    讲的不错的博客

    class:和其它的变量类型差不多,只不过class存的是一个变量类型,常与template连用

    具体用法:class 变量名。不能赋值。如:class s=bool;是编译不过的,但是class s;可以

    template:特殊的函数传参方法,可以传class类型的变量(至少我是这么理解的)

    具体用法:template<变量类型 变量名,变量类型 变量名...>函数类型 函数名(函数传参){}

    在函数定义时前面加<>,里面加上任意多个变量类型及变量名,和在小括号里的传参类似。

    如:template<class nd,int N,int M>void work(int p){nd a[1005];return;}

    然后这题虽然看了题解发了std之后AC一片一片的,但是其实真的没有那么好想。

    首先dp定义是dp[i][j][k][l]表示已经填了i位,目前累计的“赤壁之意”为j,已经分成了k段,序列的端点已经被用上了l个。

    第一维可滚动。数组大小为2*7500*50*3。空间可接受。100*7500*50*3时间可接受。(7500怎么来的等会讲)

    这里的段的内部次序已经确定,段之间的先后关系也已经确定,但是它们在原序列上的具体位置和间隔距离并不确定。

    假设目前的状态dp[i][j][k][l]=DP,i从0开始枚举,从小往大填。

    dp[i&1^1][j-2-i*2][k+1][l]+=DP*(k+1-l),表示你新开了一个段只有i+1这个数,在目前已有k个段的情况下一共有k+1种位置可插入,插入后“赤壁之意“累加-2i-2

    因为你这个数左右两边都没有值,以后填的值都比这个值大,所以abs就是两边的和分别减去i+1,所以填i+1的贡献就是-2i-2。

    但是如果已经有一个端点确定了,那么这个新段就不能加在最前面了,两个端点都确定的话同理,所以可选择位置要减去l。

    dp[i&1^1][j][k][l]+=DP*(2*k-l),表示你在某一个段的一个端点上加上了i+1这个数,k个段每个都有2个端点,但是整个序列已经确定的端点上不能加数,所以就是2k-l。

    这样的贡献是0,对于已经填上的数它一定比i+1小那么会产生i+1的贡献,另一端还没有填的一定比它大会产生-i-1的贡献抵消了。

    dp[i&1^1][j+2+2*i][k-1][l]+=DP*( k-1 ),表示你把两个段合并,k个段之间有k-1个位置来合并。合并操作并不受端点是否已经确定的影响。

    dp[i&1^1][j-1-i][k+1][l+1]+=DP*( 2-l ),表示在端点处新建一个段。

    dp[i&1^1][j+1+i][k][l+1]+=DP*( 2-l ),表示把一个段的端点延伸并设为整个序列的端点。

    至于7500是怎么来的,就是最后的答案不会超过n(n+1)/2这比较显然,开大更好,大约是5000。

    然而上来一直建新段的话会导致过程中你的积分是负的,最多u会负n(n+1)/4,大约是-2500。

    和起来就是7500。对于float128的n=50的测试点相应的小4倍。

    Lockey提出了倒着扫回去先放大数,这样的话就不用担心过程中分数会出负数了。

     1 #include<cstdio>
     2 #include<cstring>
     3 __float128 ans;int n,m,k;
     4 #define DP dp[i&1][j][k][l]
     5 int floor(__float128 x){
     6     for(int i=9;i>=0;--i)if(x>=i)return i;
     7 }
     8 void print__float128(__float128 x,int ws){
     9     int sta[55];sta[0]=0;
    10     for(int i=1;i<=ws;++i)x*=10,sta[i]=floor(x),x-=floor(x);
    11     x*=10;if(floor(x)>=5)sta[k]++;
    12     for(int i=ws;i;--i)if(sta[i]==10)sta[i]=0,sta[i-1]++;
    13     printf("%d.",sta[0]);
    14     for(int i=1;i<=ws;++i)printf("%d",sta[i]);
    15     puts("");
    16 }
    17 int main(){
    18     scanf("%d%d%d",&n,&m,&k);
    19     if(k<=8){
    20         static double dp[2][22222][55][4];
    21         #define $ 12345
    22         dp[0][$][0][0]=1;
    23         for(int i=0;i<n;++i){
    24             std::memset(dp[i&1^1],0,sizeof dp[0]);
    25             for(int j=0;j<=$+(n+1)*n/2;++j)for(int k=0;k<=50;++k)for(int l=0;l<=2;++l)if(DP>=0.998){
    26                 dp[i&1^1][j-2-i*2][k+1][ l ]+=DP*(k+1-l);
    27                 dp[i&1^1][   j   ][ k ][ l ]+=DP*(2*k-l);
    28                 dp[i&1^1][j+2+2*i][k-1][ l ]+=DP*(k-1);
    29                 dp[i&1^1][ j-1-i ][k+1][l+1]+=DP*(2-l);
    30                 dp[i&1^1][ j+1+i ][ k ][l+1]+=DP*(2-l);
    31             }
    32         }
    33         for(int j=m+$;j<=$+(n+1)*n/2;++j)ans+=dp[n&1][j][1][2];
    34     }else{
    35         static __float128 dp[2][8888][55][4];
    36         #define $ 3000
    37         dp[0][$][0][0]=1;
    38         for(int i=0;i<n;++i){
    39             std::memset(dp[i&1^1],0,sizeof dp[0]);
    40             for(int j=0;j<=$+(n+1)*n/2;++j)for(int k=0;k<=50;++k)for(int l=0;l<=2;++l)if(DP>=0.998){
    41                 dp[i&1^1][j-2-i*2][k+1][ l ]+=DP*(k+1-l);
    42                 dp[i&1^1][   j   ][ k ][ l ]+=DP*(2*k-l);
    43                 dp[i&1^1][j+2+2*i][k-1][ l ]+=DP*(k-1);
    44                 dp[i&1^1][ j-1-i ][k+1][l+1]+=DP*(2-l);
    45                 dp[i&1^1][ j+1+i ][ k ][l+1]+=DP*(2-l);
    46             }
    47         }
    48         for(int j=m+$;j<=$+(n+1)*n/2;++j)ans+=dp[n&1][j][1][2];
    49     }
    50     for(int i=1;i<=n;++i)ans/=i;
    51     print__float128(ans,k);
    52 }
    未用tmeplate。1.6k
     1 #include<cstdio>
     2 __float128 ans;int n,m,k;
     3 #define DP dp[i&1][j][k][l]
     4 int floor(__float128 x){for(int i=9;i>=0;--i)if(x>=i)return i;}
     5 void print__float128(__float128 x,int ws){
     6     int sta[55];sta[0]=0;
     7     for(int i=1;i<=ws;++i)x*=10,sta[i]=floor(x),x-=floor(x);
     8     if(floor(x*10)>=5)sta[k]++;
     9     for(int i=ws;i;--i)if(sta[i]==10)sta[i]=0,sta[i-1]++;
    10     printf("%d.",sta[0]);for(int i=1;i<=ws;++i)printf("%d",sta[i]);
    11 }
    12 int P(int a){return a<0?0:a;}
    13 template<class nd,int N,int M>void work(){
    14     static nd dp[2][N][52][3];
    15     dp[0][M][0][0]=1;
    16     for(int i=0;i<n;++i)for(int j=0;j<=M+(n+1)*n/2;++j)for(int k=i?1:0;k<=50;++k)for(int l=0;l<=2;++l)if(DP>=0.998)
    17             dp[i&1^1][P(j-2-i*2)][k+1][ l ]+=DP*(k+1-l),
    18             dp[i&1^1][     j    ][ k ][ l ]+=DP*(2*k-l),
    19             dp[i&1^1][ j+2+2*i  ][k-1][ l ]+=DP*( k-1 ),
    20             dp[i&1^1][ P(j-1-i) ][k+1][l+1]+=DP*( 2-l ),
    21             dp[i&1^1][  j+1+i   ][ k ][l+1]+=DP*( 2-l ),
    22             DP=0;
    23     for(int j=m+M;j<=M+(n+1)*n/2;++j)ans+=dp[n&1][j][1][2];
    24     for(int i=1;i<=n;++i)ans/=i;
    25     print__float128(ans,k);
    26 }
    27 int main(){
    28     scanf("%d%d%d",&n,&m,&k);
    29     if(k<=8)work<double,7777,2555>();else work<__float128,4000,1300>();
    30 }
    加template,1.1k
     1 #include<cstdio>
     2 __float128 ans;int n,m,k;
     3 #define DP dp[i&1][j][k][l]
     4 int floor(__float128 x){for(int i=9;i>=0;--i)if(x>=i)return i;}
     5 void print__float128(__float128 x,int ws){
     6     int sta[55];sta[0]=0;
     7     for(int i=1;i<=ws;++i)x*=10,sta[i]=floor(x),x-=floor(x);
     8     if(floor(x*10)>=5)sta[k]++;
     9     for(int i=ws;i;--i)if(sta[i]==10)sta[i]=0,sta[i-1]++;
    10     printf("%d.",sta[0]);for(int i=1;i<=ws;++i)printf("%d",sta[i]);
    11 }
    12 template<class nd>void work(){
    13     static nd dp[2][8888][52][3];
    14     dp[n&1][0][0][0]=1;
    15     for(int i=n;i;--i)for(int j=0;j<=(n+1)*n*3/4;++j)for(int k=0;k<=50;++k)for(int l=0;l<=2;++l)if(DP>=0.998){
    16             dp[i&1^1][j+2*i][k+1][ l ]+=DP*(k+1-l);
    17             dp[i&1^1][  j  ][ k ][ l ]+=DP*(2*k-l);
    18 if(k&&j>=2*i)dp[i&1^1][j-2*i][k-1][ l ]+=DP*( k-1 );
    19             dp[i&1^1][ j+i ][k+1][l+1]+=DP*( 2-l );
    20 if(j>=i)    dp[i&1^1][ j-i ][ k ][l+1]+=DP*( 2-l );
    21             DP=0;
    22     }
    23     for(int j=m;j<=(n+1)*n/2;++j)ans+=dp[0][j][1][2];
    24     for(int i=1;i<=n;++i)ans/=i;
    25     print__float128(ans,k);
    26 }
    27 int main(){
    28     scanf("%d%d%d",&n,&m,&k);
    29     if(k<=8)work<double>();else work<__float128>();
    30 }
    加Lockey优化,1.0k

    时间复杂度倒是差不多。

  • 相关阅读:
    export和import实现模块化
    Net Core
    DockerCon 2016
    NET Core 构成体系
    Cloud Engine
    JVM内存结构
    Signalr
    Rabbit.Rpc
    遍历指定包名下所有的类(支持jar)(转)
    httpd的简单配置(转)
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11437287.html
Copyright © 2011-2022 走看看