USACO2018 DEC(Platinum) (树上乱搞,期望+凸包)
发现这跟\(Gold\)难度简直天差地别啊。。
\(T1\)
解题思路
这道题还是很可做的,发现题意可以传化成一棵树每次从叶子节点删边,然后有\(m\)条限制,形如\(a\)在\(b\)前面删去。发现\(a\)在\(b\)前面删去其实就是\(ban\)掉一棵树上一段或两段连续的\(dfs\)序,这个讨论一下关系即可。这样就可以树剖+线段树维护,但是直接做只有\(88\)分,因为没有考虑不合法的情况,判不合法的情况可以根据删除关系建一张有向图,然后最后判断有无环即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,m,num,siz[N],top[N],son[N],id[N],fa[N],dep[N],f[N][20];
int vis[N],tot;
bool use[N],tt[N];
vector<int> v[N],G[N];
struct Segment_Tree{
#define mid ((l+r)>>1)
int sum[N<<2],tag[N<<2];
void pushdown(int x){
sum[x<<1]|=tag[x];
sum[x<<1|1]|=tag[x];
tag[x<<1]|=tag[x];
tag[x<<1|1]|=tag[x];
tag[x]=0;
}
void update(int x,int l,int r,int L,int R){
if(L>R) return ;
if(L<=l && r<=R) {sum[x]=tag[x]=1; return;}
if(tag[x]) pushdown(x);
if(L<=mid) update(x<<1,l,mid,L,R);
if(mid<R) update(x<<1|1,mid+1,r,L,R);
sum[x]=(sum[x<<1]|sum[x<<1|1]);
}
int query(int x,int l,int r,int pos){
if(l==r) return sum[x];
if(tag[x]) pushdown(x);
if(pos<=mid) return query(x<<1,l,mid,pos);
return query(x<<1|1,mid+1,r,pos);
}
#undef mid
}tree;
void dfs1(int x,int F){
siz[x]=1; fa[x]=F; int maxson=-1;
f[x][0]=F;
for(int i=1;i<=17;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=0;i<v[x].size();i++){
int u=v[x][i]; if(u==F) continue;
dep[u]=dep[x]+1; dfs1(u,x); siz[x]+=siz[u];
if(siz[u]>maxson) maxson=siz[u],son[x]=u;
}
}
void dfs2(int x,int topf){
top[x]=topf; id[x]=++num;
if(!son[x]) return;
dfs2(son[x],topf); int u;
for(int i=0;i<v[x].size();i++){
u=v[x][i]; if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
}
int jump(int x,int D){
for(int i=17;~i;i--)
if(dep[f[x][i]]>=D) x=f[x][i];
return x;
}
void dfs(int x,int F){
use[x]=1;
for(int i=0;i<v[x].size();i++){
int u=v[x][i]; if(u==F || use[u]) continue;
// cout<<u<<" "<<x<<endl;
G[u].push_back(x); dfs(u,x);
}
}
void cir(){
for(int i=1;i<=n;i++) puts("0");
exit(0);
}
void find_cir(int x){
for(int i=0;i<G[x].size();++i){
int u=G[x][i];
if(vis[u]) cir();
if(tt[u]) continue;
vis[u]=1; tt[u]=1;
find_cir(u); vis[u]=0;
}
}
int main(){
// freopen("in","r",stdin);
n=rd(),m=rd(); int x,y;
for(int i=1;i<n;i++){
x=rd(),y=rd();
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(1,0); dfs2(1,1);
while(m--){
x=rd(),y=rd(); G[x].push_back(y);
// cout<<x<<" "<<y<<endl;
if(id[y]>=id[x] && id[y]<=id[x]+siz[x]-1){
int now=jump(y,dep[x]+1);
tree.update(1,1,n,1,id[now]-1);
tree.update(1,1,n,id[now]+siz[now],n);
G[x].push_back(now);
// cout<<x<<" "<<now<<endl;
for(int i=0;i<v[x].size();i++){
int u=v[x][i];
if(id[u]>=id[now] && id[u]<=id[now]+siz[now]-1) continue;
// cout<<u<<" "<<x<<endl;
G[u].push_back(x); dfs(u,x);
}
}
else{
tree.update(1,1,n,id[x],id[x]+siz[x]-1);
dfs(x,fa[x]);
}
}
for(int i=1;i<=n;i++)
if(!tt[i]) find_cir(i);
for(int i=1;i<=n;i++) {
if(!tree.query(1,1,n,id[i])) puts("1");
else puts("0");
}
return 0;
}
\(T3\)
解题思路
神仙题。首先发现对于一个点来说它的答案一定是从自己这个点直接跳下去或者向左右两边分别找到一个点跳下去。考虑区间\([0,L]\),设\(x\)走到\(L\)的概率为\(f(x)\),那么有\(f(x)=\frac{f(x-1)+f(x+1)}{2}\),发现这是个等差数列的形式,又因为\(f(L)=1,f(0)=0\)可以解得\(f(x)=\frac{x}{L}\),那么这个人在某个点往左右两边走时左边到达\(a\)点,右边到达\(b\)点,则他获得的收益为\(V_a \frac{b-i}{b-a}+V_b \frac{i-a}{b-a}\),那么就得到一个暴力的做法,就是枚举左右端点算最大值。但发现这样复杂度太高,考虑如何能快速找到左右两点。如果把它们放到平面直角坐标系上,每个点横坐标设为位置,纵坐标设为该位置的权值。那么画个图带进去可以发现,要求的其实就是两点连线与\(x=i\)之间交点的纵坐标,那么确定这两个点就可以用凸包判断了。就是把凸包找出来,然后对于一个点来说如果它在凸包上,答案就为这个点的纵坐标,否则为它前后两个凸包上的点连线的\(x=i\)时的纵坐标。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const double eps=1e-8;
typedef long long LL;
int n,stk[N],top;
double a[N];
struct Node{
int x; LL y;
Node(int _x=0,LL _y=0){
x=_x; y=_y;
}
}node[N];
Node operator-(Node A,Node B){
return Node(A.x-B.x,A.y-B.y);
}
inline LL cross(Node A,Node B){
return A.x*B.y-A.y*B.x;
}
inline bool check(int x,int y,int z){
return cross((node[y]-node[x]),(node[z]-node[y]))>=eps;
}
inline LL calc(int x,int y,int z){
return (node[y].y*(node[z].x-node[x].x)+node[x].y*(node[y].x-node[z].x))/(node[y].x-node[x].x);
}
int main(){
scanf("%d",&n); double tmp;
for(int i=1;i<=n;i++) {
node[i].x=i; scanf("%lf",&tmp);
node[i].y=tmp*100000;
}
stk[++top]=0; node[n+1].x=n+1;
for(int i=1;i<=n+1;i++){
while(top>1 && check(stk[top-1],stk[top],i)) top--;
stk[++top]=i;
} int now=1;
for(int i=1;i<=n;i++){
while(stk[now]<i) now++;
if(stk[now]==i) printf("%lld\n",(LL)(node[i].y));
else printf("%lld\n",calc(stk[now-1],stk[now],i));
}
return 0;
}
USACO2018 DEC(Platinum) (树上乱搞,期望+凸包)的更多相关文章
- zoj 3820 Building Fire Stations(树上乱搞)
做同步赛的时候想偏了,状态总是时好时坏.这状态去区域赛果断得GG了. 题目大意:给一棵树.让求出树上两个点,使得别的点到两个点较近的点的距离最大值最小. 赛后用O(n)的算法搞了搞,事实上这道题不算难 ...
- BZOJ3573: [Hnoi2014]米特运输(树上乱搞)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1669 Solved: 1031[Submit][Status][Discuss] Descript ...
- CF809E Surprise me!(莫比乌斯反演+Dp(乱搞?))
题目大意: 给你一棵树,树上的点编号为\(1-n\).选两个点\(i.j\),能得到的得分是\(\phi(a_i*a_j)*dis(i,j)\),其中\(dis(i,j)\)表示\(a\)到\(b\) ...
- BZOJ4401:块的计数(乱搞)
Description 小Y最近从同学那里听说了一个十分牛B的高级数据结构——块状树.听说这种数据结构能在sqrt(N)的时间内维护树上的各种信息,十分的高效.当然,无聊的小Y对这种事情毫无兴趣,只是 ...
- 洛谷P5211 [ZJOI2017]字符串(线段树+乱搞)
题面 传送门 题解 为什么大佬们全都是乱搞的--莫非这就是传说中的暴力能进队,乱搞能AC-- 似乎有位大佬能有纯暴力+玄学优化\(AC\)(不算上\(uoj\)的\(Hack\)数据的话--这要是放到 ...
- bzoj 1050: [HAOI2006]旅行comf(codevs.cn 1001 舒适的路线) 快排+并查集乱搞
没用的话:好像很久没发博客了,主要是懒太蒟找不到水题.我绝对没弃坑...^_^ 还用些话:本文为博主原创文章,若转载请注明原网址和作者. 进入正题: 先pa网址: bzoj :http://www.l ...
- BZOJ_2801_[Poi2012]Minimalist Security_dfs树+特判+乱搞
BZOJ_2801_[Poi2012]Minimalist Security_dfs树+特判+乱搞 Description 给出一个N个顶点.M条边的无向图,边(u,v)有权值w(u,v),顶点i也有 ...
- VIJOS1476 旅行规划(树形Dp + DFS暴力乱搞)
题意: 给出一个树,树上每一条边的边权为 1,求树上所有最长链的点集并. 细节: 可能存在多条最长链!最长链!最长链!重要的事情说三遍 分析: 方法round 1:暴力乱搞Q A Q,边权为正-> ...
- [bzoj4796][CERC2016]Key Knocking_乱搞
Key Knocking bzoj-4796 CERC-2016 题目大意:描述没有题面短系列..题目链接 注释:$1\le n\le 10^5$. 想法: 乱搞稳AC.考试的时候调试信息又一次杀死了 ...
随机推荐
- 【Linux开发】【Qt开发】ARM QT移植详细步骤教程
ARM QT移植详细步骤教程 米尔SAM9X5和A5D3X上默认的Qt版本是4.5.3,当这个版本的Qt库不能满足实际开发需求时,可通过此方法制定Qt开发.运行环境. 移植的步骤如下: 1.下载新版q ...
- 洛谷 P5663 加工零件 & [NOIP2019普及组] (奇偶最短路)
传送门 解题思路 很容易想到用最短路来解决这一道问题(题解法),因为两个点之间可以互相无限走,所以如果到某个点的最短路是x,那么x+2,x+4也一定能够达到. 但是如何保证这是正确的呢?比如说到某个点 ...
- MATLAB图像的代数运算
1.图像旋转与缩放 bm=imread("3.png"); %subplot(1,3,1); imshow(bm); %缩放图片 %bt=imresize(bm,0.5,'near ...
- Qt读写Json
Qt操作Json 1.QJsonDocument 1.详细说明 QJsonDocument类提供了读写JSON文档的方法. QJsonDocument是一个封装了完整JSON文档的类,可以从基于UTF ...
- How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained
http://blog.originate.com/blog/2014/02/20/afimagecache-vs-nsurlcache/
- UIScrollView学习笔记
1.如何使用UIScrollView显示一张比屏幕大的图片 //创建滚动视图的对象 UIScrollView * sv = [[UIScrollView alloc]initWithFrame:CGR ...
- vue 之 双向绑定原理
一.实现双向绑定 详细版: 前端MVVM实现双向数据绑定的做法大致有如下三种: 1.发布者-订阅者模式(backbone.js) 思路:使用自定义的data属性在HTML代码中指明绑定.所有绑定起来的 ...
- Set 的合集 并集 差集
合集 ,,,,,,]; ,,]; function union() { //先将数组去重 let s1 = new Set(arr1); let s2 = new Set(arr2); //[...s ...
- Vscode添加谷歌Debug插件
1. 2.安装好 Debugger for Chrome之后,找到要进行Debug的文件 3. 4.进入到launch.json文件中进行相应的配置 配置文件内容如下: { "version ...
- luogu P3601 签到题
链接P3601 签到题 求\[\sum_{i=l}^{r} i-\phi_i\] \(l,r\leq 10^{12},\ r-l\leq 10^6\) 杜教筛似乎做不了. 然后再看\(l\),\(r\ ...