【ZJOI2012】波浪【NOIP2017】赤壁情

Description

【ZJOI2012】波浪【NOIP2017】赤壁情_第1张图片

Data Constraint

【ZJOI2012】波浪【NOIP2017】赤壁情_第2张图片

Solution

先来一波套路:①从小到大插入能够去掉绝对值的影响②dp只需要处理相对位置就可以记录答案。
fi,j,k,l 表示当前做到i,段数(连续有数的被称作一段)为j,此时对答案贡献为k,左右两个边界有多少个被填上,满足这样的状态有多少种方案。
大致分为以下几种情况:
①当前插入的值自成一段没有贴边界,贡献为-2*i
②当前插入的值自成一段有贴边界,贡献为-i
③当前插入的值加入了别的段且不使两段合并,贡献为0
④当前插入的值加入了别的段且使两段合并,贡献为+2*i
在转移的时候注意一下边界问题。
因为精度要精确到30位,不想打小数高精度可以试试__float128黑科技,只是有点慢。

Code

#include
#include
#include
#include
#include
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
typedef long long ll;
typedef double db;
typedef __float128 fl;
const int N=102,S=5000;
int n,m,o,i,j,k,l,Z;
db f[2][102][S*2+5][3],tot;
fl g[2][102][S*2+5][3],ans,TOT;
void write(fl ans){
    int tot=ans;printf("%d.",tot);
    while(o--){
        ans=(ans-tot*1.0)*10.0;
        if(!o) ans=ans+0.5;
        tot=ans;printf("%d",tot);
    }printf("\n");
}
int main(){
    scanf("%d%d%d",&n,&m,&o);
    Z=0;f[0][0][S][0]=g[0][0][S][0]=1;
    if(o<=8){
    fo(i,1,n){
        Z^=1;memset(f[Z],0,sizeof(f[Z]));
        fo(j,0,i){
            fo(k,0,S*2){
                fo(l,0,2){
                    tot=f[Z^1][j][k][l];
                    if(!tot) continue;
                    if(l<2){
                        if(j) f[Z][j][k+i][l+1]+=tot*(2-l);
                        f[Z][j+1][k-i][l+1]+=tot*(2-l);
                    }
                    f[Z][j+1][k-2*i][l]+=tot*(j+1-l);
                    if(j) f[Z][j][k][l]+=tot*(2*j-l);
                    if(j>1) f[Z][j-1][k+2*i][l]+=tot*(j-1);
                }
            }
        }
    }}
    else{
    fo(i,1,n){
        Z^=1;memset(g[Z],0,sizeof(g[Z]));
        fo(j,0,i){
            fo(k,0,S*2){
                fo(l,0,2){
                    TOT=g[Z^1][j][k][l];
                    if(!TOT) continue;
                    if(l<2){
                        if(j) g[Z][j][k+i][l+1]+=TOT*(2-l);
                        g[Z][j+1][k-i][l+1]+=TOT*(2-l);
                    }
                    g[Z][j+1][k-2*i][l]+=TOT*(j+1-l);
                    if(j) g[Z][j][k][l]+=TOT*(2*j-l);
                    if(j>1) g[Z][j-1][k+2*i][l]+=TOT*(j-1);
                }
            }
        }
    }}
    ans=0;
    if(o<=8){fo(i,S+m,2*S) ans+=f[Z][1][i][2];}
    else {fo(i,S+m,2*S) ans+=g[Z][1][i][2];}
    fo(i,1,n) ans/=i*1.0;
    write(ans);
}

你可能感兴趣的:(NOIP,ZJOI)