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]落忆枫音 描述: ...
随机推荐
- Thinking in scala (2)---- 最大公约数
gcd.scala object gcd{ def main(args:Array[String]){ println( gcd1(args(0).toInt,args(1).toInt)) prin ...
- STM32-USB那点事
STM32 USB那点事1 USB那点事2 - Custom HID例子程序解疑 USB那点事3 -使用端口2作为custom HID的传输 USB那点事5之USB通信出错 USB那点事6传输要素 S ...
- Oracle 事件
Oracle 的事物 事物是设么 事物是用于高正数据的一致性,他由一组相关的dml语句组成(增加删除语句),这组语句要么全部成功要不全部失败. 如:网上转账. 1)设置保存点 Savepoint a1 ...
- C#创建datatable (转)
C#创建datatable 方法一: DataTable tblDatas = new DataTable("Datas"); DataColumn dc = null; dc ...
- logback的日志配置文件
日志配置文件logback.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE con ...
- RF & Microarray
REF[24] 随机森林是一个很好适用于微阵列数据的分类算法: 1.即使大多数的预测变量都是噪音,RF仍然具有优秀的性能,因此不需要对基因进行预选择. 2.能够应用于变量数远远大于观测数据量的情况 3 ...
- Angular - - angular.equals
angular.equals 对比两个对象/值是否相等.支持值类型.正则表达式.数组和对象. 如果下列至少有一个是正确的,则将两个对象/值视为相等. 两个对象/值能通过===比较. 两个对象/值是同一 ...
- iPhone 屏幕分辨率
5S 640 x 1136 5 640 x 1136 4s 640 x 960 4 640 x 960 3gs 320 x 480
- js架构设计模式——理解javascript中的MVVM开发模式
理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...
- MonthCalendar控件
MonthCalendar控件 功能,直接显示月历,