题解 刮痧
还算是思路比较正常
首先发现这里 ,考虑枚举哪些怪最终被打死了
发现攻击次数是定值,令 为 中怪物血量之和
那么就要求一个 为对 集合中怪物攻击 次且均不打死的方案数
这相当于用 种颜色对 个石头染色,每次加入 这种颜色即可
然后发现还需要计算出现每种情况的概率
令 为当前死活状态为 (0 未死,1 已死)的概率
转移考虑下一次是否击杀一只怪物
系数分别是 和
统计答案就枚举击杀怪物集合,乘上集合大小产生贡献即可
复杂度
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
int a[N];
namespace force{
double ans;
void dfs(int u, double pre) {
if (u>m) {
int cnt=0;
for (int i=1; i<=n; ++i) if (a[i]<=0) ++cnt;
ans+=cnt*pre;
return ;
}
int cnt=0;
for (int i=1; i<=n; ++i) if (a[i]>0) ++cnt;
pre/=cnt;
for (int i=1; i<=n; ++i) if (a[i]>0) {
--a[i];
dfs(u+1, pre);
++a[i];
}
}
void solve() {
dfs(1, 1);
printf("%.5lf\n", ans);
}
}
namespace task{
int sum[1<<15], lg[N];
double C[110][110], f[105][1<<15], g[105][1<<15];
void solve() {
int lim=1<<n;
C[0][0]=1;
for (int i=1; i<=m; ++i) {
C[i][0]=1;
for (int j=1; j<=i; ++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
}
for (int i=0; i<n; ++i) lg[1<<i]=i;
sum[0]=0;
for (int s=1; s<lim; ++s) sum[s]=sum[s-(s&-s)]+a[lg[s&-s]];
f[0][0]=1;
for (int i=0; i<m; ++i) {
for (int s=0; s+1<lim; ++s) {
for (int j=0; j<n; ++j) if (!(s&(1<<j)) && i-sum[s]>=a[j]-1)
f[i+1][s|(1<<j)]+=C[i-sum[s]][a[j]-1]*f[i][s]/(n-__builtin_popcount(s));
f[i+1][s]+=f[i][s]/(n-__builtin_popcount(s));
}
}
for (int s=0; s<lim; ++s) g[0][s]=1;
for (int i=1; i<=m; ++i) {
for (int s=1,t; s<lim; ++s) {
t=lg[s&-s];
for (int j=0; j<a[t]&&j<=i; ++j)
g[i][s]+=C[i][j]*g[i-j][s^(1<<t)];
}
}
double ans=0;
for (int s=0; s<lim; ++s) if (sum[s]<=m)
ans+=f[m][s]*g[m-sum[s]][(~s)&(lim-1)]*__builtin_popcount(s);
printf("%.5lf\n", ans);
}
}
int main()
{
freopen("scraping.in", "r", stdin);
freopen("scraping.out", "w", stdout);
n=read(); m=read();
for (int i=0; i<n; ++i) a[i]=read();
// force::solve();
task::solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通