NOIP2012 Day2
来源:互联网 发布:js 正则 可有可无 编辑:程序博客网 时间:2024/06/05 00:58
T1 同余方程
套一个exgcd模板即可
#include<bits/stdc++.h>using namespace std;int ex_gcd(int a,int b,int &x,int &y){ if (!b){ x=1; y=0; return a; } else{ int t=ex_gcd(b,a%b,y,x); y=y-a/b*x; return t; }} int main(){ int a,b,x,y; scanf("%d%d",&a,&b); ex_gcd(a,b,x,y); printf("%d\n",x<0?x%b+b:x); return 0;}
T2 借教室
解法1
比较裸的区间更新 区间查询线段树
注意卡常 毕竟是
#include<bits/stdc++.h>using namespace std;#define N 1000010void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int a[N];struct Segment_Tree{ #define Lc p<<1 #define Rc p<<1|1 int add[N<<2],Mn[N<<2]; void up(int p){ Mn[p]=min(Mn[Lc],Mn[Rc]); } void down(int p){ add[Lc]+=add[p]; add[Rc]+=add[p]; Mn[Lc]-=add[p]; Mn[Rc]-=add[p]; add[p]=0; } void build(int l,int r,int p){ if (l==r){ Mn[p]=a[l]; return; } int mid=(l+r)>>1; build(l,mid,Lc); build(mid+1,r,Rc); up(p); } void update(int l,int r,int p,int pl,int pr,int x){ if (l==pl && r==pr){ add[p]+=x; Mn[p]-=x; return; } int mid=(l+r)>>1; down(p); if (pr<=mid) update(l,mid,Lc,pl,pr,x); else if (pl>mid) update(mid+1,r,Rc,pl,pr,x); else update(l,mid,Lc,pl,mid,x),update(mid+1,r,Rc,mid+1,pr,x); up(p); } int query(int l,int r,int p,int pl,int pr){ if (l==pl && r==pr) return Mn[p]; int mid=(l+r)>>1; down(p); if (pr<=mid) return query(l,mid,Lc,pl,pr); else if (pl>mid) return query(mid+1,r,Rc,pl,pr); else return min(query(l,mid,Lc,pl,mid),query(mid+1,r,Rc,mid+1,pr)); }}T;int main(){ int n,m,i; rd(n),rd(m); for (i=1;i<=n;i++) rd(a[i]); T.build(1,n,1); for (i=1;i<=m;i++){ int x,l,r; rd(x),rd(l),rd(r); if (T.query(1,n,1,l,r)<x){ printf("-1\n%d\n",i); return 0; } T.update(1,n,1,l,r,x); } printf("0\n"); return 0;}
解法2
考虑二分恰好不合法的那个位置
判断时只需用差分前缀和维护每个时间借的教室的个数
同样
#include<bits/stdc++.h>using namespace std;#define N 1000010void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int n,m,a[N],p[N],l[N],r[N];long long sum[N];bool check(int x){ int i; memset(sum,0,sizeof(sum)); for (i=1;i<=x;i++){ sum[l[i]]+=p[i]; sum[r[i]+1]-=p[i]; } long long tmp=0; for (i=1;i<=n;i++){ tmp+=sum[i]; if (tmp>a[i]) return 0; } return 1;}int main(){ int i; rd(n),rd(m); for (i=1;i<=n;i++) rd(a[i]); for (i=1;i<=m;i++) rd(p[i]),rd(l[i]),rd(r[i]); if (check(m)){ printf("0\n"); return 0; } int l=1,r=m,res=m; while (l<=r){ int mid=(l+r)>>1; if (!check(mid)) res=mid,r=mid-1; else l=mid+1; } printf("-1\n%d\n",res); return 0;}
解法3
可以用每次不合法就撤销一些操作的方法来实现
同样用差分前缀和维护
如果当前点不满足 就从后向前撤销操作 直到满足为止
看最后剩下的操作编号 +1即为不满足的编号
#include<bits/stdc++.h>using namespace std;#define N 1000010void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int a[N],p[N],l[N],r[N];long long sum[N];int main(){ int i,n,m; rd(n),rd(m); for (i=1;i<=n;i++) rd(a[i]); for (i=1;i<=m;i++){ rd(p[i]),rd(l[i]),rd(r[i]); sum[l[i]]+=p[i]; sum[r[i]+1]-=p[i]; } long long now=0; int t=n; for (i=1;i<=n;i++){ now+=sum[i]; while (now>a[i]){ sum[l[t]]-=p[t]; sum[r[t]+1]+=p[t]; if (l[t]<=i && r[t]>=i) now-=p[t]; t--; } } if (t==n) printf("0\n"); else printf("-1\n%d\n",t+1); return 0;}
T3 疫情控制
如果已知最大时间 一个军队肯定尽量向上跳 因为这样可以覆盖更多的点
那么可以二分最大时间 用倍增求最多跳到的点
但是有一种情况 就是一个子树内的点跑到另一个子树内
可以先把能跑到1的军队处理出来 然后贪心处理
如果当前子树已经可以被其他的军队完全覆盖 那就可以让到1的军队全部出去
否则先留下剩余时间最少的一个
然后把还未覆盖的点按到1的时间排序 同时用一个小顶堆维护到1的军队的剩余时间
每次用小的匹配小的
如果当前点有留下军队 就要比较当前的堆顶和留下的军队 选取剩余时间少的用掉 多的放回堆内
在堆中如果堆顶时间不够跑 就弹出
有两种情况
1:堆顶军队剩余时间
2:堆顶军队剩余时间
因此这个贪心是正确的
#include<bits/stdc++.h>using namespace std;#define N 50010#define K 16#define INF (0x3f3f3f3f3f3f3f3f)void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}struct edge{ int nxt,t,s;}e[N<<1];int head[N],edge_cnt,fa[N][K],n,m,a[N],top[N],Head[N];long long dis[N][K],f[N];void add_edge(int x,int y,int z){ e[edge_cnt]=(edge){head[x],y,z}; head[x]=edge_cnt++;}struct node{ int id,s; bool operator <(const node &_)const{ return s<_.s; }}Q1[N];struct poi{ int nxt; long long t;}A[N];struct heap{ int h; long long a[N]; void ins(long long x){ a[++h]=x; int i=h; while (i>1){ if (a[i>>1]>a[i]) swap(a[i>>1],a[i]),i>>=1; else break; } } void del(){ a[1]=a[h--]; int i=1; while ((i<<1)<=h){ int j=i<<1; if (j+1<=h && a[j+1]<a[j]) j++; if (a[i]>a[j]) swap(a[i],a[j]),i=j; else break; } }}Q;bool b[N];long long Mx;void dfs(int x,int f,int tp,long long Dis){ Mx=max(Mx,Dis); fa[x][0]=f; top[x]=tp; int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t,val=e[i].s; if (to==f) continue; dis[to][0]=val; dfs(to,x,!tp?to:tp,Dis+val); }}long long init(){ dfs(1,0,0,0); int i,j; for (i=1;i<K;i++) for (j=1;j<=n;j++){ int x=fa[j][i-1]; fa[j][i]=fa[x][i-1]; dis[j][i]=dis[j][i-1]+dis[x][i-1]; } int Mx1=0; for (i=head[1];~i;i=e[i].nxt) Mx1=max(Mx1,e[i].s); return Mx+Mx1;}bool filled(int x,int f){ if (b[x]) return 1; else if (e[head[x]].nxt==-1) return 0; int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (to==f) continue; if (!filled(to,x)) return 0; } return 1;}bool check(long long t){ int i,j; memset(b,0,sizeof(b)); for (i=head[1];~i;i=e[i].nxt) Head[e[i].t]=-1; int rec_cnt=0,h=0; Q.h=0; for (i=1;i<=m;i++){ int x=a[i]; long long sum=0; for (j=K-1;j>=0 && x>1;j--) if (sum+dis[x][j]<=t){ sum+=dis[x][j]; x=fa[x][j]; } if (x<=1) A[rec_cnt]=(poi){Head[top[a[i]]],t-sum},Head[top[a[i]]]=rec_cnt++; else b[x]=1; } for (i=head[1];~i;i=e[i].nxt){ int to=e[i].t,val=e[i].s; if (!filled(to,1)){ int pos=-1; f[to]=INF; for (j=Head[to];~j;j=A[j].nxt) if (f[to]>A[j].t) pos=j,f[to]=A[j].t; for (j=Head[to];~j;j=A[j].nxt) if (j!=pos) Q.ins(A[j].t); Q1[++h]=(node){to,val}; } else for (j=Head[to];~j;j=A[j].nxt) Q.ins(A[j].t); } sort(Q1+1,Q1+1+h); for (i=1;i<=h;i++){ int x=Q1[i].id,y=Q1[i].s; long long t1=f[x],t2=INF; while (Q.h && Q.a[1]<y) Q.del(); if (Q.h) t2=Q.a[1]; if (t1==INF && t2==INF) return 0; if (t1>t2) Q.del(),Q.ins(t1); } return 1;}int main(){ int i; memset(head,-1,sizeof(head)); rd(n); for (i=1;i<n;i++){ int x,y,z; rd(x),rd(y),rd(z); add_edge(x,y,z); add_edge(y,x,z); } rd(m); for (i=1;i<=m;i++) rd(a[i]); long long l=0,r=init(),ans=-1; while (l<=r){ long long mid=(l+r)>>1; if (check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%lld\n",ans); return 0;}
Date:2017/10/23
By CalvinJin
阅读全文
0 0
- NOIP2012 Day2
- NOIP2012复赛DAY2
- NOIP2012提高组Day2
- NOIP2012 day2 T3 疫情控制
- noip2012 day2 T3 疫情控制
- NOIP2012 Day2 T2 借教室
- NKOJ-1887 借教室 【NOIP2012 day2】
- NOIP2012提高组day2第2题 借教室
- NOIP2012提高组Day2 第3题 疫情控制
- NOIP2012 Day2 借教室-二分答案+差分
- Noip2012 Day2 T1 同余方程(扩展欧几里得)
- Noip2012 Day2 T2 借教室 (二分答案+差分)
- NOIp2012
- NOIP2012复赛提高组day2(A:同余方程 B:借教室 C:疫情控制)
- Day2
- day2
- DAY2
- day2
- 无限轮播+pulltorefresh刷新
- lecture7,Training Neural Networks, Part 2
- 代码大全 读书笔记(2)
- 项目请求参数封装
- js预处理阶段arguments深度解剖
- NOIP2012 Day2
- java接口的使用
- Druid大数据实时处理的开源分布式系统——Historical Node
- Oracle数据库、实例、用户、表空间、表之间的关系
- <二分答案加验证||最小生成树>bzoj 1821 部落划分
- 腾讯浏览服务接入文档
- iOS AutoLayout 简单运用(纯代码)
- <考试题> codevs 5440 运输计划 (二分+lca+dfs序+树上差分)
- 1701 H2王建瑜 连续第十二天