标签:log inline turn 大于 价值 else 个数 bit 连通
花掉了自己用来搞学科的时间做了这道题……
一道类似的题:Here
考虑拆开绝对值计算贡献。那么我们对于\(1\)到\(N\)的排列,从小到大地将插入它们插入排列中。
假设我们现在计算到了数\(i\),这意味着前\(i-1\)个数已经被插入到了排列中。考虑当前如何计算\(i\)的贡献。
不难发现:在最终的排列中,\(i\)的贡献与它和前\(i-1\)个数和边界的相邻情况有关。如果\(i\)某一边与边界相邻,会产生\(0\)的贡献;某一边与小于\(i\)的数相邻,会产生\(i\)的贡献;某一边与大于\(i\)的数相邻,会产生\(-i\)的贡献。
但是在这里大于\(i\)的数还没有被插入,所以这里必须要强制数\(i\)与前\(i-1\)个数和边界的相邻情况才能够在当前阶段计算出\(i\)对序列价值的贡献。
故设\(f_{i,j,k,l}\)表示放完了前\(i\)个数、数列中存在\(j\)个连通块(定义连通块为一段极长区间,满足这一段区间任意的相邻的两个数都被强制定为相邻,也就是说在之后的转移中,这一段区间内不能插入数)、数列总价值为\(k-5000\)、有\(l\)个边界已经与某个数强制相邻的方案数。
转移:
\(a.\)一边与边界相邻,一边不与当前产生的连通块相邻,产生\(-i\)的价值,方案数为\(2-l\)
\(b.\)一边与边界相邻,一边与当前产生的连通块相邻,产生\(i\)的价值,方案数为\(2-l\),要求\(j \neq 0\)
\(c.\)两边均与当前产生的连通块相邻,产生\(2i\)的价值,方案数为\(j-1\),要求\(j \geq 2\)
\(d.\)两边均不与当前产生的连通块相邻,产生\(-2i\)的价值,方案数为\(j+1-l\)
\(e.\)一边与当前产生的连通块相邻,另一边不与当前产生的连通块相邻,产生\(0\)的价值,方案数为\(j*2-l\),要求\(j \neq 0\)
注意到\(de\)两种转移方案数都减去了\(l\),因为对于两端都不与边界相邻的连通块,可以选择左右之一与当前的数相邻,但是有一段与边界相邻的连通块只有一端可以。
最后的答案就是\(\frac{\sum\limits_{i=5000+M}^{10000} f_{N,1,i,2}}{n!}\)
然后这鬼题还要数据类型分治……\(K \leq 8\)使用long double,\(K \leq 30\)使用__float128
// luogu-judger-enable-o2
#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c)){
if(c == ‘-‘)
f = 1;
c = getchar();
}
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ ‘0‘);
c = getchar();
}
return f ? -a : a;
}
namespace db{long double dp[2][110][10010][3];}
namespace flt{__float128 dp[2][110][10010][3];}
int N , M , K;
template < class T >
void out(T ans){
cout << "0.";
ans *= 10;
for(int i = 1 ; i <= K ; ++i){
cout << (int)(ans + (K == i) * 0.5);
ans = (ans - (int)ans) * 10;
}
}
template < class T >
inline void solve(T dp[][110][10010][3]){
T ans = 0;
dp[0][0][5000][0] = 1;
int now = 0;
for(int i = 1 ; i <= N ; ++i){
now ^= 1;
memset(dp[now] , 0 , sizeof(dp[now]));
for(int j = 0 ; j <= min(i - 1 , M) ; ++j)
for(int k = 0 ; k <= 10000 ; ++k)
for(int p = 0 ; p <= 2 ; ++p)
if(dp[now ^ 1][j][k][p]){
if(k - 2 * i >= 0)
dp[now][j + 1][k - 2 * i][p] += dp[now ^ 1][j][k][p] * (j + 1 - p);
if(j)
dp[now][j][k][p] += dp[now ^ 1][j][k][p] * (j * 2 - p);
if(j >= 2 && k + 2 * i <= 10000)
dp[now][j - 1][k + 2 * i][p] += dp[now ^ 1][j][k][p] * (j - 1);
if(p != 2){
if(k - i >= 0)
dp[now][j + 1][k - i][p + 1] += dp[now ^ 1][j][k][p] * (2 - p);
if(j && k + i <= 10000)
dp[now][j][k + i][p + 1] += dp[now ^ 1][j][k][p] * (2 - p);
}
}
}
for(int i = M ; i <= 5000 ; ++i)
ans += dp[now][1][5000 + i][2];
for(int i = 1 ; i <= N ; ++i)
ans /= i;
out(ans);
}
int main(){
#ifndef ONLINE_JUDGE
//freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
N = read();
M = read();
K = read();
if(K <= 8)
solve(db::dp);
else
solve(flt::dp);
return 0;
}
标签:log inline turn 大于 价值 else 个数 bit 连通
原文地址:https://www.cnblogs.com/Itst/p/10328072.html