首页 > 其他分享 >NOIP2016 提高组 换教室

NOIP2016 提高组 换教室

时间:2024-11-24 20:55:26浏览次数:11  
标签:NOIP2016 ch int 提高 db 教室 rd buf dis

NOIP2016 提高组 换教室

非常简单的一道期望 dp,但是自己做的时候严重想复杂导致做了3天……

算法一

容易发现任意两次课之间转移的期望代价只和当前起终点的状态有关,因此每次转移可以独立出来了。现在想怎么算这个期望。

一个结论:期望的计算:如果概率为 \(k\) 的代价为 \(w_1\),概率为 \((1-k)\) 的代价为 \(w_2\),那么期望就是概率乘代价,即 \(k \times w1+(1-k) \times w2\)。(来自 题解 P1850 【换教室】- by qwaszx

爆搜每个位置申请或不申请,时间复杂度是 \(O(\binom{n}{m})\)。实现的比较好所以得了 80pts。

算法二

改成 dp,记 \(f_{i, j, 0/1}\) 表示 \(1 \sim i\),用了 \(j\) 次申请,第 \(i\) 申请 / 不申请,最小期望代价和。转移是显然的,分讨一下就好。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
using namespace std;
using ll = long long;
using db = double; 
char buf[100], *p1 = buf, *p2 = buf;
inline int gc(){
	return (p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 100, stdin), p1 == p2) ? EOF : *p1++;
}
inline db rd(){
	db x = 0; char ch; bool f = 1;
	while(!isdigit(ch = gc())) f ^= (ch == '-');
	do x = x * 10 + (ch ^ 48); while(isdigit(ch = gc()));
	if(ch == '.'){
		db k = 0.1;
		while(isdigit(ch = gc())) x += (ch ^ 48) * k, k /= 10;
	}
	return f ? x : -x;
}
const int N = 2005;
const int M = 305;
const int inf = 0x3f3f3f3f;
int dis[M][M];
int a[N], b[N];
db k[N], f[N][N][2];
int n, m, v, e;
void floyed(){
	F(k, 1, v) F(i, 1, v) F(j, 1, v) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
void Min(double &x, double y){
	(x > y) &&(x = y);
}
double solve(){
	F(i, 0, n) F(j, 0, m) f[i][j][0] = f[i][j][1] = 1e9;
	f[1][1][1] = f[1][0][0] = 0;
	F(i, 2, n){
		F(j, 0, m){
			f[i][j][0] = min(f[i - 1][j][0] + dis[a[i - 1]][a[i]], f[i - 1][j][1] + dis[a[i - 1]][a[i]] * (1 - k[i - 1]) + dis[b[i - 1]][a[i]] * k[i - 1]);
			if(j){
				f[i][j][1] = min(f[i - 1][j - 1][0] + dis[a[i - 1]][a[i]] * (1 - k[i]) + dis[a[i - 1]][b[i]] * k[i],
								 f[i - 1][j - 1][1] + dis[a[i - 1]][a[i]] * (1 - k[i - 1]) * (1 - k[i])
								 					+ dis[b[i - 1]][a[i]] * k[i - 1] * (1 - k[i])
													+ dis[a[i - 1]][b[i]] * (1 - k[i - 1]) * k[i]
													+ dis[b[i - 1]][b[i]] * k[i - 1] * k[i]
				);
			}
		}
	}
	db ans = 1e9;
	F(i, 0, m) Min(ans, f[n][i][0]), Min(ans, f[n][i][1]);
	return ans;
}
signed main(){
	n = rd(), m = rd(), v = rd(), e = rd();
	F(i, 1, n) a[i] = rd();
	F(i, 1, n) b[i] = rd();
	F(i, 1, n) k[i] = rd();
	F(i, 1, v) F(j, 1, v) dis[i][j] = (i == j) ? 0 : inf;
	F(i, 1, e){
		int x = rd(), y = rd(), z = rd();	
		dis[x][y] = min(dis[x][y], z);
		dis[y][x] = dis[x][y];
	}
	floyed();
	printf("%.2lf", solve());
	return fflush(0), 0;
}

总结

本题主要困住我的地方在于我很自然地把贡献拆成了当前点申请和不申请两部分去分别看待,导致每步转移要四个贡献合起来,而不是两个,搞得非常复杂,因此暴力都分析了很长的事件。对期望的认识还不够。

标签:NOIP2016,ch,int,提高,db,教室,rd,buf,dis
From: https://www.cnblogs.com/superl61/p/18566346

相关文章

  • P1125 [NOIP2008 提高组] 笨小猴 C语言
    先说思路:创建了一个函数来判断是否是质数,然后将字符串输入,因为题干中说长度小于100,再加上\0,所以要把长度定义为101,之后对每一个字母用双层循环进行遍历,外层用count来计数,若超过maxn则赋新值,minn同样,之后再对maxn-minn得到的数进行判断即可,之后根据题意用if-else语句即可完成......
  • FDTD仿真提高工作站性能
    性能测试问题:对lumericalfdtd软件,为什么在https://optics.ansys.com/hc/en-us/articles/4403780894355-FDTD-Performance-Benchmarks网页中,使用IntelXeonScalable8375C2.9GHz、64cores、256GBRAM的高性能工作站能够获得2106.1mNodes/s的求解器速度,我自己的高性能工作站为I......
  • 在 Windows 10 和 Windows 11 中,启用“提高指针精确度”和显示指针轨迹的功能,您可以通
    在Windows10和Windows11中,启用“提高指针精确度”和显示指针轨迹的功能,您可以通过系统设置或者直接修改注册表来实现。下面是两种方法的详细步骤:方法1:通过系统设置启用启用“提高指针精确度”:打开设置:点击 开始菜单,然后选择 设置(齿轮图标),或按 Win+I 快捷键打开设......
  • [题解](更新中)[test06]2024/11/23 模拟赛 / 2023牛客OI赛前集训营-提高组(第三场) A~C
    原题页面:https://ac.nowcoder.com/acm/contest/65194Statements&Solution:https://www.luogu.com.cn/problem/U507978\(80+80+50+24=234\)。A贪心+双指针。根据贪心思想,大值选大、小值选小。我们按绝对值从大到小给\(a\)排序,再按从小到大给\(b\)排序,取双指针\(l=1,r=m\)......
  • 提高组字符串专题1
    A[NOIP2020]字符串匹配枚举循环节\(AB\),找到最多的循环节,剩下的一定包含在\(C\)。然后可以发现的是\(F(C)=F((AB)^kC),k>1\),那么就只用考虑\(C\)和\(ABC\)的贡献即可。复杂度\(\mathcal{O}(N\logN)\)。#include<bits/stdc++.h>usingnamespacestd;constexprintN......
  • 打卡信奥刷题(290)用C++工具信奥P2347[普及组/提高] [NOIP1996 提高组] 砝码称重
    [NOIP1996提高组]砝码称重题目描述设有1g1\mathrm{g}1g、2g......
  • C++提高编程-STL
    STL初识容器算法迭代器初识vector存放内置数据类型#include<vector>#include<algorithm>voidmyPrint(intx){ cout<<x<<'';}voidtest01(){ //创建vector容器 vector<int>v; //向容器中插入数据 v.push_back(10); v.push_back(20); v.......
  • 提高ADC采样精度:C语言中的滤波与取平均值技巧
    在嵌入式系统中,ADC(模数转换器)是常用的组件,用于将模拟信号转换为数字信号。然而,由于噪声和其他干扰因素,ADC采样值可能会波动,导致读数不稳定。为了提高ADC读数的准确性,常用的方法是进行滤波和取平均值。本文将详细介绍如何在C语言中实现ADC采样值的滤波和取平均值,并提供详细的代......
  • 【MySQL】提高篇—理论讲解与案例分析:实践练习:编写复杂查询、创建视图和存储过程
    关系数据库是存储和管理数据的核心工具。随着数据量的不断增加和业务需求的复杂化,开发者和数据分析师需要掌握编写复杂查询、创建视图和存储过程的技能。这些技能不仅能够提高数据操作的效率,还能确保数据处理的准确性和安全性。复杂查询:能够从多个表中提取相关数据,进行联接、......
  • 考公刷题,如何才能做到有效提高?
    在这个“不拼爹”的时代里,考公务员成了不少小伙伴们的首选。但是,要想在这条路上走得稳当,可不是一件容易的事儿。如何通过刷题来提升自己的竞争力呢?我们就来说说那些能让你刷题效率翻倍的小技巧吧!1.制定合理的学习计划刷题不是漫无目的地做题,而是要有计划地进行。想象一下,如......