HNOI2015 Day 1
HNOI2015的题还是非常漂亮的,几道题都有很大的借鉴意义,都有很强的思考性
T1亚瑟王(概率论)
描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4008
我们可以发现这个模型可以转化成有r个机会给n个人,每个人对每个机会都有一定的概率拿,求收益的期望
那么记f[i][j]为第i个人有j个机会的概率,那么可以得出
f[i+1][j]+=f[i][j]*(1-p[i])^j
f[i+1][j-1]+=f[i][j]*(1-(1-p[i])^j)
就可以完美解决这个问题了
这道题的重点是把这个模型进行转化(可以直观了理解吧n和r对换过来),否则按 f[i][j]为第i轮到第j个的概率的话搞到死都做不出(我就是这样QAQ),在做概率题的时候模型转换是第一步也是最重要的一步
Code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 222
double f[maxn][maxn],p[maxn];
int d[maxn];
int main(){
int t;
scanf("%d",&t);
while (t--) {
memset(f,,sizeof(f));
int n,r;
scanf("%d%d",&n,&r);
for (int i=;i<=n;i++) scanf("%lf%d",p+i,d+i);
memset(f,,sizeof(f));
f[][r]=;
double ans=;
for (int i=;i<=n;i++) {
double tmp=;
for (int j=;j<=r;j++){
tmp*=-p[i];
f[i+][j]+=f[i][j]*tmp;
f[i+][j-]+=f[i][j]*(-tmp);
ans+=f[i][j]*(-tmp)*d[i];
}
}
printf("%.10lf\n",ans);
}
return ;
}
T2:接水果(数据结构)
描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4009
ORZ clj出的神题
由于省特派员送温暖,各种写法都水过了QAQ
连暴力在八中都能过这是什么回事QAQ
先讲下水法把= =
解法一:(暴力)
直接读入每个盘子后排下序,用lca判断覆盖就离线tarjan搞,复杂度O(n^2),水过了!!!
解法二:(树链剖分+主席树+可持久化treap)
先把那棵树树链剖分掉,然后考虑在没有主席树的远古时代人们用的方法——平衡树,那么我们对每一个树节点建立一棵主席树,每个主席树树节点维护一个可持久化Treap,存起点在该点在该树节点的重链上,终点在主席树的该区间中所有盘子的w值,那么我们每次就可以二分答案,把log n棵主席树,每棵主席树中的log n个区间中小于该答案的盘子数算出来= =总的时间复杂度O(n log^4 n)~~~
解法三:(点剖+树链剖分+主席树套权值线段树)
由于某同学的口胡,我至今仍搞不清为何要先点剖= =,大致思想跟解法二差不多,但是就吧treap换成权值线段树,总时间复杂度貌似为(O(n log^3 n)(某同学说的))
解法四:(树上莫队+平衡树)
既然题目允许离线那就考虑用树上莫队解决,对当前的两个询问点u,v维护他们的相对差(也就是u到根的信息-v到根的信息),lca上的信息需要特判一下,如果我的盘子的起点和终点都在我的相对差中就加入平衡树,然后在log n查询即可,分块上每根号n个一块即可通过本题,总的时间复杂度O(nsqrt(n)log n)
解法五:(正解,扫描线+树状数组套权值线段树)
还是离线,把每个点重标号为其dfs序,每个询问抽象成二维平面坐标中的点(u,v)。可发现每个盘子所控制的坐标为若干个矩形区域。
具体来说,如果两个盘子的坐标与其lca不同,那么就是起点与终点在u,v的子树中是符合要求的
否则,就是一个在子树中,另一个不在lca的那个子树中
那么问题就变成了一个经典问题:询问在某点上的矩形的第k大
扫描线+树状数组套权值线段树秒过
时间复杂度O(n log^2 n)
Code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 41000
#define maxk 24
vector<int> e[maxn];
int st[maxn],ed[maxn],dfn[maxn],dep[maxn];
int f[maxn][maxk],clo;
void dfs(int u,int fa) {
st[u]=ed[u]=dfn[u]=++clo;
f[u][]=fa;dep[u]=dep[fa]+;
for (int i=;i<maxk;i++) {
if (f[f[u][i-]][i-]==) break;
f[u][i]=f[f[u][i-]][i-];
}
for (int i=;i<e[u].size();i++) {
if (e[u][i]==fa) continue;
dfs(e[u][i],u);
ed[u]=ed[e[u][i]];
}
}
inline int up(int x,int y) {
for (int i=;i<maxk;i++) if (y&(<<i)) x=f[x][i];
return x;
}
inline int lca(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
x=up(x,dep[x]-dep[y]);
if (x==y) return x;
for (int i=maxk-;i+;i--) {
if (f[x][i]==f[y][i]) continue;
x=f[x][i];y=f[y][i];
}
return f[x][];
}
struct qnode{int x,y1,y2,z,flag;}s[maxn*];
int l;
inline void add(int x,int y1,int y2,int w,int flag) {
s[++l]=(qnode){x,y1,y2,w,flag};
}
typedef pair<int,int> ii;
#define fi first
#define se second
ii b[maxn];
bool cmp(int x,int y) {return dfn[b[x].fi]<dfn[b[y].fi];}
bool cmp1(qnode x,qnode y){return x.x<y.x;}
struct node{
int lc,rc,s;
}t[maxn*];
int cnt;
#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define mid (l+r>>1)
void insert(int &x,int l,int r,int y,int z){
if (x==) x=++cnt;
t[x].s+=z;
if (l==r) return ;
if (mid>=y) insert(lc(x),l,mid,y,z);
else insert(rc(x),mid+,r,y,z);
}
int n;
#define lowbit(x) ((x)&(-x))
int r[maxn];
#define inf 0x7fffffff
inline void ins(int x,int y,int z) {
for (;x<=n+;x+=lowbit(x)) insert(r[x],,inf,y,z);
}
vector<int> list[];
#define pb push_back
int solve(int l,int r,int deep,int &k) {
int sum=;
for (int i=;i<list[deep].size();i++) sum+=t[list[deep][i]].s;
if (sum<k) {k-=sum;return -;}
if (sum>=k&&l==r) return l;
list[deep+].clear();
for (int i=;i<list[deep].size();i++) if (t[list[deep][i]].lc) list[deep+].pb(t[list[deep][i]].lc);
int tmp=solve(l,mid,deep+,k);
if (tmp!=-) return tmp;
list[deep+].clear();
for (int i=;i<list[deep].size();i++) if (t[list[deep][i]].rc) list[deep+].pb(t[list[deep][i]].rc);
return solve(mid+,r,deep+,k);
}
inline int que(int x,int y,int k) {
list[].clear();
for (;y;y-=lowbit(y)) if (r[y]) list[].pb(r[y]);
return solve(,inf,,k);
}
int main(){
int p,q;
scanf("%d%d%d",&n,&p,&q);
for (int i=;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].pb(y);e[y].pb(x);
}
dfs(,);
static ii a[maxn];
static int w[maxn],k[maxn];
for (int i=;i<=p;i++) scanf("%d%d%d\n",&a[i].fi,&a[i].se,w+i);
for (int i=;i<=q;i++) scanf("%d%d%d\n",&b[i].fi,&b[i].se,k+i);
for (int i=;i<=p;i++) {
int v=lca(a[i].fi,a[i].se);
if (v!=a[i].fi&&v!=a[i].se) {
add(st[a[i].fi],st[a[i].se],ed[a[i].se],w[i],);
add(ed[a[i].fi]+,st[a[i].se],ed[a[i].se],w[i],-);
add(st[a[i].se],st[a[i].fi],ed[a[i].fi],w[i],);
add(ed[a[i].se]+,st[a[i].fi],ed[a[i].fi],w[i],-);
}else {
if (v!=a[i].fi) swap(a[i].fi,a[i].se);
v=up(a[i].se,dep[a[i].se]-dep[a[i].fi]-);
add(,st[a[i].se],ed[a[i].se],w[i],);
add(st[v],st[a[i].se],ed[a[i].se],w[i],-);
add(ed[v]+,st[a[i].se],ed[a[i].se],w[i],);
add(n+,st[a[i].se],ed[a[i].se],w[i],-);
add(st[a[i].se],,st[v]-,w[i],);
add(ed[a[i].se]+,,st[v]-,w[i],-);
add(st[a[i].se],ed[v]+,n,w[i],);
add(ed[a[i].se]+,ed[v]+,n,w[i],-);
}
}
static int id[maxn];
for (int i=;i<=q;i++) id[i]=i;
sort(id+,id++q,cmp);
sort(s+,s++l,cmp1);
int r=;
static int ans[maxn];
for (int i=;i<=l;i++) {
while (r<=q&&dfn[b[id[r]].fi]<s[i].x) ans[id[r]]=que(b[id[r]].fi,dfn[b[id[r]].se],k[id[r]]),r++;
ins(s[i].y1,s[i].z,s[i].flag);
ins(s[i].y2+,s[i].z,-s[i].flag);
}
for (int i=;i<=q;i++) printf("%d\n",ans[i]);
return ;
}
T3:菜肴制作(拓扑序,贪心,构造)
描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4010
首先判环这个就不用说了吧
然后我们必须优先让最小的尽量前,那么我们就必须且只能把最小的点反向边所能遍历到的点删掉
考虑删最小的点的前一个点,一定是去掉最小点反向边入度为0的最大点删去
可以继续贪心构造
那么我们每次就反向遍历求出联通块再做次拓扑序即可
优先队列 O(n log n)解决
Code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 100010
struct edges{
int to,next;
}edge[maxn];
int next[maxn],l,in[maxn];
inline void addedge(int x,int y) {
edge[++l]=(edges){y,next[x]},next[x]=l;in[y]++;
}
bool b[maxn];
vector<int> a;
#define pb push_back
inline void tuopu(int x) {
static priority_queue<int> q;
while (!q.empty()) q.pop();
q.push(x);b[x]=;a.clear();
while (!q.empty()) {
int u=q.top();q.pop();
a.pb(u);
for (int i=next[u];i;i=edge[i].next) {
if (b[edge[i].to]) continue;
in[edge[i].to]--;
if (in[edge[i].to]==){
b[edge[i].to]=;
q.push(edge[i].to);
}
}
}
}
int n;
bool iscircle() {
static int q[maxn];
int r=;
for (int i=;i<=n;i++) if (in[i]==) q[++r]=i;
for (int l=,u=q[l];l<=r;u=q[++l])
for (int i=next[u];i;i=edge[i].next){
in[edge[i].to]--;
if (in[edge[i].to]==) q[++r]=edge[i].to;
}
return r!=n;
}
int cnt,bo[maxn];
bool bfs(int x) {
cnt++;
static int q[maxn];
q[]=x;
for (int l=,u=q[],r=;l<=r;u=q[++l])
for (int i=next[u];i;i=edge[i].next) {
if (b[edge[i].to]) continue;
in[edge[i].to]++;
if (bo[edge[i].to]!=cnt) {
q[++r]=edge[i].to;
bo[edge[i].to]=cnt;
}
}
}
int main(){
int T;
scanf("%d",&T);
while (T--) {
int m;
scanf("%d%d",&n,&m);
memset(next,,sizeof(next));
memset(b,,sizeof(b));
memset(bo,,sizeof(bo));
memset(in,,sizeof(in));
l=;cnt=;
for (int i=;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
addedge(y,x);
}
if (iscircle()) {printf("Impossible!\n");continue;}
for (int i=;i<=n;i++) {
if (b[i]) continue;
bfs(i);
tuopu(i);
for (int i=a.size()-;i+;i--) printf("%d ",a[i]);
}
printf("\n");
}
return ;
}
这几道题是非常的漂亮的,像第一二题的转化真的是想不到啊= =第三题也得有很好的直觉在能做= =
HNOI2015 Day 1的更多相关文章
- 【BZOJ4008】[HNOI2015]亚瑟王 期望
[BZOJ4008][HNOI2015]亚瑟王 Description 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑. 他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最 ...
- BZOJ4009: [HNOI2015]接水果
4009: [HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她 ...
- 【BZOJ】【4011】【HNOI2015】落忆枫音
拓扑排序+DP 题解:http://blog.csdn.net/PoPoQQQ/article/details/45194103 http://www.cnblogs.com/mmlz/p/44487 ...
- 【BZOJ】【4010】【HNOI2015】菜肴制作
拓扑排序 这题是要求N个点的一个拓扑序,且满足以下条件:编号1的位置尽可能靠前,在此基础上编号2的位置尽可能靠前…… 我看到这题的第一感觉:将拓扑排序用的队列改为优先队列,编号越小越早出来. 但是连样 ...
- bzoj 4010: [HNOI2015]菜肴制作 拓扑排序
题目链接: 题目 4010: [HNOI2015]菜肴制作 Time Limit: 5 Sec Memory Limit: 512 MB 问题描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴 ...
- HNOI2015滚粗记
HNOI2015滚粗记 经过两天的苦战,艰难的HNOI终于结束了.感觉这次HNOI自己还是收获了许多. \(Day1\)打的很是艰难,题目一下就有种晕头转向的感觉.开场\(20min\)自己还在读题时 ...
- BZOJ 4008: [HNOI2015]亚瑟王( dp )
dp(i, j)表示考虑了前i张牌, 然后还有j轮的概率. 考虑第i+1张牌: 发动的概率 : p = dp(i, j) * (1 - (1-p[i+1])^j) 没发动的概率 : dp(i, j) ...
- BZOJ 4011: [HNOI2015]落忆枫音( dp )
DAG上有个环, 先按DAG计数(所有节点入度的乘积), 然后再减去按拓扑序dp求出的不合法方案数(形成环的方案数). ---------------------------------------- ...
- BZOJ 4010: [HNOI2015]菜肴制作( 贪心 )
把图反向,然后按拓扑序贪心地从大到小选, 最后输出.set比priority_queue慢... --------------------------------------------------- ...
- HNOI2015 Day 2题解
昨天做了HNOI day 2,感觉好像还是可做的,想当年什么splay还是高级算法,现在点剖什么就老考了简直丧病,虽然第二题还没写那就先当下嘴巴选手吧= = T1:[HNOI2015]落忆枫音 描述: ...
随机推荐
- BZOJ2733 [HNOI2012]永无乡 【线段树合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- Centos7.2 编译安装PHP7
PHP7,编译安装: 环境:centos7.2 (注意:因为我用的nginx, 此配置参数没有考虑到apache,所以不合适需要用apache的朋友照搬过去运行,但是可以参考.) 直接下载P ...
- UVa 10523 - Very Easy !!!
题目大意:给你一个公式,直接按照式子计算就可以了,要用到大数. import java.io.*; import java.util.*; import java.math.*; class Main ...
- UVa 990 - Diving for Gold
题目大意:一个潜水者去海底寻找金子,已知有n个有金子的地点,分别给出他们的深度和价值.但是由于潜水者只有一瓶氧气,所以他只能在海底呆有限的时间,问他如何才能在这有限的时间里获得尽可能多的金子,并打印出 ...
- jfreechart图表汉字乱码问题解决方案
系统工作迁移环境 linux centos 6.5 tomcat8 mysql5.6 系统部署上之后,所有的jfreechart图表上的汉字,全部乱码. 如图: 经分析: 1)数据库动态读出来的是正常 ...
- iOS 之 Quartz2D
1. Quartz2D 之 简单介绍 2. Quartz2D 之 简单使用 3. Quartz2D 之 绘制文本
- Linux 系统分区
合理的系统分区,便于后期管理和提高文件的搜索速度 分区格式说明 linux分区不同于windows,linux下硬盘设备名为(IDE硬盘为hdx(x为从a—d)因为IDE硬盘最多四 个,SCSI,SA ...
- hcharts中文网 一个js图表库
http://www.bossidc.com/info/gongju/2013/0717/2133.html hcharts源码包下载 http://www.hcharts.cn/demo/hig ...
- 如何在windows xp下实现声音内录
问题描述: 用屏幕录制软件录制一个视频,能够成功录制视频,但无法录制视频里面的声音. 问题原因: 因为现在的多数声卡,均无法直接通过声卡自身的功能实现内录和立体声混音. 这是由于声卡芯片厂商迫于RIA ...
- CentOS 6.5下NFS安装配置
[root@local /]# yum -y install nfs-utils rpcbind3.创建共享目录:[root@local /]# mkdir /sharestore4.NFS共享文件路 ...