【ZJOI2012】波浪【NOIP2017】赤壁情
阿新 • • 發佈:2019-01-24
Description
Data Constraint
Solution
先來一波套路:①從小到大插入能夠去掉絕對值的影響②dp只需要處理相對位置就可以記錄答案。
設
大致分為以下幾種情況:
①當前插入的值自成一段沒有貼邊界,貢獻為-2*i
②當前插入的值自成一段有貼邊界,貢獻為-i
③當前插入的值加入了別的段且不使兩段合併,貢獻為0
④當前插入的值加入了別的段且使兩段合併,貢獻為+2*i
在轉移的時候注意一下邊界問題。
因為精度要精確到30位,不想打小數高精度可以試試__float128黑科技,只是有點慢。
Code
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<math.h>
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);
}