【JZOJ A组】【NOIP2019模拟2019.9.11】考试(test)

题目

【问题描述】
小 S 要参见一场考试,这场考试一共有 k 道题目。每道题目有分值 ??,难度 zi 和
类型 si。这些题目一共有 m 中不同的类型。
由于小 S 偏科严重,所以对不同类型的题目熟练度可能不同,在第 i 种类型的题
目熟练度为 yi。
为了简化问题,我们认为当小 S 以 y 的熟练度做难度为 z 分值为 a 的题目时,
会获得 a ⋅ (1 − max (0,1 − ??)2) 的分数。
众所周知,做题不顺利可能影响心态和发挥,在这里我们认为,如果小 S 在某一
道题目的得分低于总分的 64%,那么接下来做题熟练度会下降。具体来说,接下来的
第 i 道题熟练度会下降 ci%。每一道题只会受到之前最后一次分数低于 64% 的影响。
(就是说如果第 t 道题的分数小于满分的 64%,那么第 t+i 道题的熟练度会下降 Ci%。
同时,如果有多道题分数小于满分的 64%,只有最后一次会有影响。比如说第 1 道题分
数小于 64%那么第 3(即 1+2)题会下降 C2%,接下来第 4 题又低于 64%那么第 5(即 4+1)
题会下降 C1%。)
根据目前的描述,已经可以确定出小 S 在每道题的得分了。但是小 S 有 n 瓶神
奇的饮料,在做题时喝掉第 i 瓶饮料可以让这道题的熟练度提高 xi%。每瓶饮料只能
在一道题喝,做一道题时可以喝多瓶饮料。
熟练度的下降和上升是依次进行,每次都按当前的百分比计算。简单来说,就是在
原来的熟练度上乘 1 ± u%。
现在问小 S 的总分最高是多少。
【输入格式】
从输入文件 test.in 中读入数据。
第一行三个整数n, m, k,分别表示饮料的瓶数、题目类型的数量和试题的数量。
第二行 n 个整数 x1, x2, ⋯ , ??,表示饮料能带来的提升
第三行 m 个整数 y1, ?2, ⋯ , ??,表示每种题目类型的熟练度。
第四行 k − 1 个整数 c1, c2, ⋯ , ck−1,表示做题不顺利对之后熟练度的下降程度。
接下来 k 行,每行三个整数 ai, si, zi,分别表示题目的分值、类型和难度。
【输出格式】
输出到文件 test.out 中。
输出一行一个实数,表示答案。四舍五入后保留两位小数输出。
【样例 1 输入】
1 1 2
10
100
50
100 1 260
100 1 200
【样例 1 输出】
2019 年非专业级软件能力认证提高级(第二轮) 第二次认证 考试(test) 第 3 页 共 8 页
141.72
【样例 1 解释】
一共一瓶饮料,可以选择在做第一题或第二题时喝。
如果在做第二题时喝:
做第一题的能力为 100,得分为 100 × (1 − (1 −
100
260)2) = 62 22
169。
由于分数低于 64,所以第二题的能力会下降 50%,又由于饮料可以提高 10%,
所以实际能力为 100 × 50% × 110% = 55。
于是第二题的得分为 100 × (1 − (1 −
55
200)2) = 47 7
16。
总得分为 109 1535
2704 分。
可以类似计算出在选择在做第一题时喝的得分为 141 121
169
分,所以最高分为
141 121
169 分。
【样例 2】
见选手目录下的 test/test2.in 与 test/test2.ans。

【数据范围】
对于 100%的测试点,保证0 ≤ n ≤ 10,1 ≤ si ≤ ? ≤ 10,1 ≤ ? ≤ 5 × 105, 0 ≤ ??−1 ≤ ??−2 ≤ ⋯ ≤ ?1 ≤ 100,1 ≤ ??, ??, ?? ≤ 105, 1 ≤ ?? ≤ 1000。

思路

根据题意DP和状压DP

注意这题的题目又臭又长,细节多,稍有不顺,便会像我一样爆0

代码

#include<bits/stdc++.h>
using namespace std;
const int N=27,maxK=5e5+77;
int n;
double x[N];
int m,y[N];
int K,a[maxK],s[maxK],z[maxK];
double c[maxK];
inline double sqr(double x){return x*x;}
double pro[1<<10],f[110][110][1<<10];
inline void update(double &x,double y){y>x?x=y:0;}
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	scanf("%d%d%d",&n,&m,&K);
	for(int i=0; i<n; i++)
		scanf("%lf",&x[i]),x[i]=(100+x[i])/100;
	for(int i=1; i<=m; i++)
		scanf("%d",&y[i]);
	for(int i=1; i<K; i++)
		scanf("%lf",&c[i]),c[i]=(100-c[i])/100;
	for(int i=1; i<=K; i++)
		scanf("%d%d%d",&a[i],&s[i],&z[i]);
	if(n==0){
		double ans=0;
		for(int i=1,lst=0; i<=K; i++)
		{
			double p=y[s[i]]*(lst?c[i-lst]:1),sco=a[i]*(1-sqr(max(0.0,1-p/z[i])));
			ans+=sco;
			if(sco<a[i]*0.64)
				lst=i;
		}
		printf("%.2lf\n",ans);
		return 0;
	}
	pro[0]=1;
	for(int i=1; i<1<<n; i++)
		for(int j=0; j<n; j++)
			if(i>>j&1)
			{
				pro[i]=pro[i^1<<j]*x[j];
				break;
			}
	memset(f,128,sizeof f);
	f[0][0][0]=0;
	for(int i=0; i<K; i++)
		for(int j=0; j<=i; j++)
			for(int s1=0;s1<1<<n;++s1)
				if(f[i][j][s1]>=0)
					for(int s2=s1;s2<1<<n;s2=(s2+1)|s1)
					{
						double p=y[s[i+1]]*(j?c[i+1-j]:1)*pro[s2^s1];
						double sco=a[i+1]*(1-sqr(max(0.0,1-p/z[i+1])));
						if(a[i+1]*0.64-sco>0)
							update(f[i+1][i+1][s2],f[i][j][s1]+sco);
						else
							update(f[i+1][j][s2],f[i][j][s1]+sco);
					}
	double ans=0;
	for(int j=0; j<=K; j++)
		for(int s1=0;s1<1<<n;s1++)
			ans=max(ans,f[K][j][s1]);
	printf("%.2lf\n",ans);
	return 0;
}
发布了703 篇原创文章 · 获赞 392 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/100785463
今日推荐