[THUPC 2023 初赛] 最后的活动
题目背景
各位亲爱的《La Lumière: Scarlet Intense Flame》玩家:
感谢您一直给予《La Lumière: Scarlet Intense Flame》的支持与厚爱。我们非常遗憾地宣布,《La Lumière: Scarlet Intense Flame》将于 2023 年 3 月 5 日 16:00 停止运营服务。
停止运营相关时间表如下:
……
题目描述
元老级二次元手游《La Lumière: Scarlet Intense Flame》将于今年 3 月停止运营服务。作为这款游戏的忠实玩家,小 S 希望能在游戏的最后一次活动中刷到一个特殊的分数,以此为近十年来与这款游戏共度的难忘时光画上一个圆满的句号。
《La Lumière: Scarlet Intense Flame》中的每种活动都有其独特的规则,而最后一次活动是 Chase Festival。在 Chase Festival 中,玩家需要多次攻略每次随机生成的多层迷宫,每次退出迷宫时根据在迷宫中各层击杀怪物的评价独立结算本次随机迷宫的分数。每次挑战迷宫时的流程简化如下:
-
选择挑战的随机迷宫的难度。小 S 是这款游戏的资深玩家,因此在本题中假定小 S 总是挑战最高难度的迷宫。最高难度的迷宫最深为 N N N 层。确定难度后,从随机生成的迷宫的第 1 层开始挑战。
-
进行第 i i i 层的挑战。挑战第 i i i 层时,小 S 有可能挑战失败,挑战成功并获得普通评价,或者挑战成功并获得高评价。如果小 S 选择保守的挑战策略,则有 p i , 0 p_{i,0} pi,0 的概率挑战失败,有 p i , 1 p_{i,1} pi,1 的概率挑战成功并获得普通评价,有 p i , 2 p_{i,2} pi,2 的概率挑战成功并获得高评价;如果小 S 选择激进的挑战策略,则有 q i , 0 q_{i,0} qi,0 的概率挑战失败,有 q i , 1 q_{i,1} qi,1 的概率挑战成功并获得普通评价,有 q i , 2 q_{i, 2} qi,2 的概率挑战成功并获得高评价。
-
获得普通评价时,在当前层获得 s i , 1 s_{i,1} si,1 的分数;获得高评价时,在当前层获得 s i , 2 s_{i,2} si,2 的分数。这部分获得的分数不会直接加算到玩家的总分数中,而是在退出迷宫时结算。如果挑战成功,且当前不是最后一层( i < N i<N i<N),则跳转到第 3 步,选择是否继续挑战;否则( i = N i=N i=N),退出迷宫并跳转到第 4 步进行结算。
-
如果挑战失败,则强制退出迷宫,跳转到第 4 步。
-
-
如果当前不是最后一层,玩家可以选择是否继续挑战下一层。如果选择继续,则返回第 2 步;否则退出当前迷宫,跳转到第 4 步进行结算。
-
本次迷宫的分数结算:如果因为失败而强制退出,则当前层不获得任何奖励,且本次迷宫中之前各层累积的分数需要乘上惩罚系数 c c c(为了使最终分数为整数,游戏会对惩罚后的分数先求和再下取整);除了强制退出之外,玩家主动退出或者通关迷宫后退出都可以获得全部尚未结算的分数。
小 S 想得到的目标分数是一个比较大的分数,因此小 S 需要先大量刷最高难度的迷宫,再在接近目标分数时根据当前剩余的分数选择相对稳定的策略,以确保活动结束时能恰好获得目标分数。小 S 不会编程,因此小 S 找到了你,希望你能帮忙计算当剩余分数在 1 1 1 至 M M M 分之间,仅按照上述的流程挑战迷宫,并采用最佳策略时,最终能够恰好达到目标分数的最大概率。
输入格式
输入的第一行包含三个整数 N , M , c ′ N, M, c' N,M,c′,其中 N N N 和 M M M 的含义与题面相同, c ′ = 100 c c'=100c c′=100c。保证 1 ≤ N ≤ 6 1\le N\le 6 1≤N≤6, 1 ≤ M ≤ 10000 1\le M\le 10000 1≤M≤10000, 0 ≤ c ′ ≤ 100 0\le c'\le 100 0≤c′≤100。
接下来 N N N 行,每行输入八个整数 s i , 1 , s i , 2 , u i , 0 , u i , 1 , u i , 2 , v i , 0 , v i , 1 , v i , 2 s_{i,1},s_{i,2},u_{i,0},u_{i,1},u_{i,2}, v_{i,0}, v_{i,1}, v_{i,2} si,1,si,2,ui,0,ui,1,ui,2,vi,0,vi,1,vi,2,其中 s i , 1 s_{i,1} si,1 与 s i , 2 s_{i,2} si,2 分别表示挑战时普通评价和高评价对应的分数; u i , j u_{i,j} ui,j 和 v i , j v_{i,j} vi,j 分别表示使用保守的挑战策略及激进的挑战策略时,对应结果的概率权重: p i , j = u i , j u i , 0 + u i , 1 + u i , 2 p_{i,j}=\dfrac{u_{i,j}}{u_{i,0}+u_{i,1}+u_{i,2}} pi,j=ui,0+ui,1+ui,2ui,j, q i , j = v i , j v i , 0 + v i , 1 + v i , 2 q_{i,j}=\dfrac{v_{i,j}}{v_{i,0}+v_{i,1}+v_{i,2}} qi,j=vi,0+vi,1+vi,2vi,j。保证 1 ≤ s i , 1 ≤ s i , 2 ≤ 10000 1\le s_{i, 1} \le s_{i, 2}\le 10000 1≤si,1≤si,2≤10000, 0 ≤ u i , j , v i , j ≤ 10000 0\le u_{i,j}, v_{i,j}\le 10000 0≤ui,j,vi,j≤10000 且 u i , 1 + u i , 2 ≥ 1 u_{i,1}+u_{i,2}\ge 1 ui,1+ui,2≥1, v i , 1 + v i , 2 ≥ 1 v_{i,1}+v_{i,2}\ge 1 vi,1+vi,2≥1。
输出格式
输出一行 M M M 个实数,其中第 i i i ( 1 ≤ i ≤ M 1\le i\le M 1≤i≤M)个实数表示当距离目标分数恰好还剩 i i i 分时,在最优策略下能够恰好获得 i i i 分的最大概率。 当你输出中的每个实数与相应标准输出的绝对误差不超过 1 0 − 6 10^{-6} 10−6 时,我们认为你的输出是正确的。
样例 #1
样例输入 #1
2 8 50
3 4 0 1 1 0 1 1
4 5 1 2 1 1 1 2
样例输出 #1
0.125000000000000000 0.140625000000000000 0.515625000000000000 0.564453125000000000 0.135009765625000000 0.328369140625000000 0.548858642578125000 0.625278472900390625
样例 #2
样例输入 #2
见附件中的 2.in
样例输出 #2
见附件中的 2.ans
提示
子任务
对于 100 % 100\% 100% 的数据,保证 1 ≤ N ≤ 6 1\le N\le 6 1≤N≤6, 1 ≤ M ≤ 10000 1\le M\le 10000 1≤M≤10000, 0 ≤ c ′ ≤ 100 0\le c'\le 100 0≤c′≤100, 1 ≤ s i , 1 ≤ s i , 2 ≤ 10000 1\le s_{i,1}\le s_{i, 2}\le 10000 1≤si,1≤si,2≤10000, 0 ≤ u i , 0 , u i , 1 , u i , 2 , v i , 0 , v i , 1 , v i , 2 ≤ 10000 0\le u_{i, 0}, u_{i, 1}, u_{i, 2}, v_{i, 0}, v_{i, 1}, v_{i, 2}\le 10000 0≤ui,0,ui,1,ui,2,vi,0,vi,1,vi,2≤10000, u i , 1 + u i , 2 ≥ 1 u_{i,1}+u_{i,2}\ge 1 ui,1+ui,2≥1, v i , 1 + v i , 2 ≥ 1 v_{i,1}+v_{i,2}\ge 1 vi,1+vi,2≥1。
提示
《La Lumière: Scarlet Intense Flame 2》将于 2023 年春暖花开的时节与大家相见!
题目来源
来自 2023 清华大学学生程序设计竞赛暨高校邀请赛(THUPC2023)初赛。
题解等资源可在 https://github.com/THUSAAC/THUPC2023-Pre 查看。
f
[
i
]
f[i]
f[i]表示当距离目标分数恰好还剩
i
i
i 分时,在最优策略下能够恰好获得
i
i
i 分的最大概率
不难发现该得分仅和
i
i
i相关,因此就可以dp,dp中途会用到
f
i
f_i
fi,因此可以先预设一个
f
i
f_i
fi迭代完重新计算的
f
i
f_i
fi会更接近原来的
f
i
f_i
fi
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define MAXN (10)
#define MAXM (10010)
double f[MAXM];
int n,m,c;
double s[MAXN][3],u[MAXN][3],v[MAXN][3];
double p[MAXN][3],q[MAXN][3];
double ck(int i,int now,int aimscores) {
if(i>n) return 0;
auto F = [&] (int c) {return c>=0?f[c]:0;};
double p1=max(F(aimscores-s[i][1]-now),ck(i+1,now+s[i][1],aimscores));
double p2=max(F(aimscores-s[i][2]-now),ck(i+1,now+s[i][2],aimscores));
int sc=now*c/100;
double u=p[i][0]*F(aimscores-sc)+p[i][1]*p1+p[i][2]*p2;
double v=q[i][0]*F(aimscores-sc)+q[i][1]*p1+q[i][2]*p2;
return max(u,v);
}
int main()
{
// freopen("E.in","r",stdin);
// freopen(".out","w",stdout);
cin>>n>>m>>c;
For(i,n) {
For(j,2) cin>>s[i][j];
Rep(j,3) cin>>u[i][j];
int s=u[i][0]+u[i][1]+u[i][2];
Rep(j,3) p[i][j]=u[i][j]/s;
Rep(j,3) cin>>v[i][j];
s=v[i][0]+v[i][1]+v[i][2];
Rep(j,3) q[i][j]=v[i][j]/s;
}
f[0]=1;
For(i,m) {
double l=0,r=1;
Rep(tt,36) {
double m=(l+r)/2;
f[i]=m;
double pm=ck(1,0,i);
if(pm>m) l=m;else r=m;
}
f[i]=l;
}
For(i,m) {
printf("%.9lf ",f[i]);
}
return 0;
}