HDU3625:Examining the Rooms
题目大意
思路
我们可以考虑,我们炸了i个门,形成了j个环的总数,因为如果我炸开一个环上一个点,我就可以连锁反应把这个环给一锅端了,所以 d p [ i ] [ j ] = ( i − 1 ) × d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − 1 ] dp[i][j]=(i-1)\times dp[i-1][j]+dp[i-1][j-1] dp[i][j]=(i−1)×dp[i−1][j]+dp[i−1][j−1],我们发现这个东西就是第一类斯特林数,又因为第一个房间不能炸,然后概率就是 d p [ i ] [ j ] − d p [ i − 1 ] [ j − 1 ] ( 减 去 第 一 个 房 间 被 炸 了 的 总 数 ) n ! \frac{dp[i][j]-dp[i-1][j-1](减去第一个房间被炸了的总数)}{n!} n!dp[i][j]−dp[i−1][j−1](减去第一个房间被炸了的总数),所以答案就是 ∑ i = 1 k d p [ n ] [ i ] − d p [ n − 1 ] [ i − 1 ] n ! \sum_{i=1}^{k}\frac{dp[n][i]-dp[n-1][i-1]}{n!} ∑i=1kn!dp[n][i]−dp[n−1][i−1]
代码被HDU针对
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Int register int
#define int long long
#define MAXN 35
int n,k;
int s[MAXN][MAXN];
int fac[MAXN];
void init()
{
fac[0]=s[0][0]=1;
for (Int i=1;i<=20;++i)
{
fac[i]=fac[i-1]*i;
s[i][0]=0;s[i][i]=1;
for (Int j=1;j<i;++j)
s[i][j]=s[i-1][j-1]+s[i-1][j]*(i-1);
}
}
void read (int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
x*=f;return;
}
void write (int x)
{
if (x<0){x=-x;putchar('-');}
if (x>9) write (x/10);
putchar(x%10+'0');
}
signed main()
{
init();
int times;
read (times);
while (times--)
{
read (n),read (k);
double ans=0;
for (Int i=1;i<=k;++i)
ans+=(s[n][i]-s[n-1][i-1])*1.0/fac[n];
printf ("%.4lf\n",ans);
}
return 0;
}