NOIP2012 提高组 Day 2
http://www.cogs.pro/cogs/page/page.php?aid=16
期望得分:100+100+0=0
实际得分:100+20+0=120
T2线段树标记下传出错
T1 同余方程
时间限制:1 s 内存限制:128 MB
【题目描述】
求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。
【输入格式】
输入只有一行,包含两个正整数 a, b,用一个空格隔开。
【输出格式】
输出只有一行,包含一个正整数X0,即最小正整数解。输入数据保证一定有解。
【样例输入】
3 10
【样例输出】
7
【数据范围】
对于 40%的数据,2 ≤b≤ 1,000;
对于 60%的数据,2 ≤b≤ 50,000,000;
对于 100%的数据,2 ≤a, b≤ 2,000,000,000。
拓展欧几里得算法,原理:http://www.cnblogs.com/TheRoadToTheGold/p/6645383.html
方程可化为ax+by=1
方程ax+by=g 有解的条件是 g是gcd(a,b)的倍数
所以a,b一定互质
所以求出的x若为负数,x=x+ b/gcd(a,b)=x+b
#include<cstdio>
using namespace std;
long long exgcd(int a,int b,long long x,long long &y)
{
if(!b)
{
x=;y=;
return y;
}
long long t=exgcd(b,a%b,x,y);
x=y;y=t-(long long)a/b*x;
return x;
}
int main()
{
freopen("mod.in","r",stdin);
freopen("mod.out","w",stdout);
int a,b;
long long x=,y=;
scanf("%d%d",&a,&b);
x=exgcd(a,b,x,y);
if(x<) x+=b;
printf("%lld",x);
}
T2 借教室
时间限制:1 s 内存限制:128 MB
【题目描述】
在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。
面对海量租借教室的信息,我们自然希望编程解决这个问题。
我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份 订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租 借教室(包括第sj天和第tj天),每天需要租借dj个教室。
我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提 供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教 室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申 请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。
现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改 订单。
【输入格式】
第一行包含两个正整数n,m,表示天数和订单的数量。
第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的教室数量。
接下来有m行,每行包含三个正整数dj,sj,tj,表示租借的数量,租借开始、结束分别在 第几天。
每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。
【输出格式】
如果所有订单均可满足,则输出只有一行,包含一个整数 0。否则(订单无法完全满足) 输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。
【样例输入】
4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
【样例输出】
-1
2
【输入输出样例说明】
第 1 份订单满足后,4 天剩余的教室数分别为 0,3,2,3。第 2 份订单要求第 2 天到 第 4 天每天提供 3 个教室,而第 3 天剩余的教室数为 2,因此无法满足。分配停止,通知第 2 个申请人修改订单。
【数据范围】
对于 10%的数据,有1 ≤ n,m ≤ 10;
对于 30%的数据,有1 ≤ n,m ≤ 1000;
对于 70%的数据,有1 ≤ n,m ≤ 10^5;
对于 100%的数据,有1 ≤ n,m ≤ 10^6,0 ≤ ri,dj ≤ 10^9,1 ≤ sj ≤ tj ≤ n。
用线段树维护区间剩余教室最小值
O(mlogn*常数。。)
codevs、COGS 可AC,洛谷上TLE 90分
#include<cstdio>
#include<algorithm>
#define N 1000001
using namespace std;
int n,m,opl,opr,w,p;
bool ok;
class tree
{
private:
struct node
{
int l,r,minn,f;
}tr[N*];
public:
void build(int k,int l,int r)
{
tr[k].l=l;tr[k].r=r;
if(l==r)
{
scanf("%d",&tr[k].minn);
return;
}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
tr[k].minn=min(tr[k<<].minn,tr[k<<|].minn);
}
void down(int k)
{
tr[k<<].minn-=tr[k].f;
tr[k<<|].minn-=tr[k].f;
tr[k<<].f+=tr[k].f;
tr[k<<|].f+=tr[k].f;
tr[k].f=;
}
void change(int k)
{
if(ok) return;
if(tr[k].l>=opl&&tr[k].r<=opr)
{
if(tr[k].minn<w)
{
printf("-1\n%d",p);
ok=true;
}
else
{
tr[k].minn-=w;
tr[k].f+=w;
}
return;
}
if(tr[k].f) down(k);
int mid=tr[k].l+tr[k].r>>;
if(opl<=mid) change(k<<);
if(opr>mid) change(k<<|);
tr[k].minn=min(tr[k<<].minn,tr[k<<|].minn);
}
}t;
int main()
{
scanf("%d%d",&n,&m);
t.build(,,n);
for(p=;p<=m;p++)
{
scanf("%d%d%d",&w,&opl,&opr);
t.change();
if(ok) return ;
}
printf("");
return ;
}
官方解法:二分
二分判断第x份订单是否可以满足要求
利用前缀和
O(n logm)
#include<cstdio>
#include<cstring>
#define M 1000001
int jiao[M],ding[M],q[M],z[M];
long long s[M];
int n,m,ans;
int read()
{
int x=,ss=getchar();
while(ss<''||ss>'') {ss=getchar();}
while(ss>=''&&ss<=''){x=ss-''+x*;ss=getchar();}
return x;
}
bool check(int x)
{
memset(s,,sizeof(s));
int tot=;
for(int i=;i<=x;i++)
s[q[i]]+=ding[i],s[z[i]+]-=ding[i];
for(int i=;i<=n;i++)
{
tot+=s[i];
if(jiao[i]<tot) return false;
}
return true;
}
int erfen(int l,int r)
{
while(l<=r)
{
int m=(l+r)>>;
if(!check(m)) r=m-,ans=m;
else l=m+;
}
return ans; }
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
jiao[i]=read();
for(int i=;i<=m;i++)
{ding[i]=read();q[i]=read();z[i]=read();}
erfen(,m) ? printf("-1\n%d",ans):printf("");
}
T3 疫情控制
时间限制:2 s 内存限制:128 MB
【题目描述】
H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是树中的根节点。
H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境 城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境 城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是, 首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在 一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等 于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
【输入格式】
第一行一个整数 n,表示城市个数。
接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从 城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。
接下来一行一个整数 m,表示军队个数。
接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎 的城市的编号。
【输出格式】
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
【样例输入】
4
1 2 1
1 3 2
3 4 3
2
2 2
【样例输出】
3
【输入输出样例说明】
第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需 时间为 3 个小时。
【数据范围】
保证军队不会驻扎在首都。
对于 20%的数据,2≤ n≤ 10;
对于 40%的数据,2 ≤n≤50,0<w <10^5;
对于 60%的数据,2 ≤ n≤1000,0<w <10^6;
对于 80%的数据,2 ≤ n≤10,000;
对于 100%的数据,2≤m≤n≤50,000,0<w <10^9
首要思维:二分
二分一个时间,判断是否能够控制疫情
因为二分固定了时间,
若以点x为根的子树中,有叶子节点没有被控制
那么要么子树x中的军队向上跑,看能否控制叶子节点
要么 不是x子树中的军队跑到 x到根节点路径上的任意一个点
一、枚举城市i,
若在规定时间内能到达根节点,
用结构体t记录它到根节点后的剩余时间、从根节点的哪个孩子到的。
若在规定时间内不能到达根节点,
因为二分固定了时间,所以一直向上跑,
到达在规定规定时间内深度最小的点 (向上跑到最远),同时在这个点建立检查点
这个向上跑到最远总不能枚举一步一步的跑,倍增优化
二、dfs,判断以哪些点为根的子树需要军队移动过去
枚举根节点的孩子j,若子树j需要军队移动
用结构体g记录点j、到根节点的距离
三、现在要做的,是给g中的每个城市匹配一个军队
所以,若待匹配军队的数目<待匹配城市的数目,直接return false
否则
将t中的军队按剩余时间升序排序
g中的城市按到根节点的距离升序排序
四、枚举每个军队i,同时枚举城市j
若军队从点k到达的根节点,且k还需要军队去建立检查点
军队i匹配城市k
若军队从k到达根节点,但k不需要军队去建立检查点
判断当前军队i的剩余时间, 能否到达城市j
若能到,匹配城市j与军队k,j转向下一个待匹配城市
否则继续
因为i是当前军队中剩余时间最少的军队
j是当前城市中到根节点最近的城市
i若不能匹配j,也就不能匹配j后面的城市
i若能匹配j,i后面的军队更有可能匹配j后面的城市
本题中二分起了相当重要的作用
二分不单单是为了log的时间复杂度,更重要的是二分能
将 求值问题转化为判定性问题
考试时没做出来 最大原因是没想到二分
其次,第四步将选择问题转化为匹配问题
考试时一直在如何处理一个军队到了根节点再往哪儿走
这样又要考虑最短距离,又要判断点是否已有军队
何不整体的看待这一问题?
AC代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 50001
using namespace std;
int n,m,army[N],now;
long long ans,l=,mid,r,d[N][],sum;
int to[N*],front[N],nextt[N*],val[N*],f[N][],p,tot;
bool v[N];
int point_sum,use_sum;
struct node3//待匹配的城市
{
int dis,id;//dis:城市到根节点的距离,id:城市编号
}g[N];
bool cmp2(node3 k,node3 h) {return k.dis<h.dis;}
struct node2//待匹配的军队
{
int left,bl;//left:到达根节点后剩余时间 ,bl:从根节点的哪个孩子到的根节点
}t[N];
bool cmp1(node2 k,node2 h) {return k.left<h.left;}
struct node
{
int bl,wh;//bl:属于根节点的哪个节点的子树,wh:城市编号
long long dis;//到根节点的距离
}e[N],cur;
queue<node>q;
void add(int u,int v,int w)
{
to[++tot]=v; nextt[tot]=front[u]; front[u]=tot; val[tot]=w;
}
void bfs()
{
for(int i=front[];i;i=nextt[i])
{
e[to[i]].bl=to[i];
e[to[i]].dis=val[i];
e[to[i]].wh=to[i];
f[to[i]][]=;
d[to[i]][]=val[i];
q.push(e[to[i]]);
}
while(!q.empty())
{
cur=q.front();q.pop();
for(int i=front[cur.wh];i;i=nextt[i])
{
if(f[to[i]][]||to[i]==) continue;
e[to[i]].bl=cur.bl;
e[to[i]].wh=to[i];
e[to[i]].dis=cur.dis+val[i];
f[to[i]][]=cur.wh;
d[to[i]][]=val[i];
q.push(e[to[i]]);
}
}
}
void dfs(int x)//v[i]=true表示以i为根的子树中的叶子节点需要被控制(即没有控制
{
bool ok=false,ok2=true;//ok2:细节,叶子节点特殊判断
//因为叶子节点ok=false,而v不一定要=true
for(int i=front[x];i;i=nextt[i])
{
if(to[i]==f[x][]) continue;
ok2=false;
if(!v[to[i]])
{
dfs(to[i]);
if(!v[to[i]]) ok=true;
}
}
if(!ok&&!ok2) v[x]=true;
}
bool check(long long k)
{
memset(v,,sizeof(*v)*(n+));
use_sum=point_sum=;
//use_sum:待匹配的军队数,point_sum:待匹配的城市数
for(int i=;i<=m;i++)
{
if(e[army[i]].dis>k)//规定时间内不能到达根节点
{
now=army[i];sum=;
for(int j=p;j>=;j--) //去他能去的最远节点建检查点
if(f[now][j]&&d[now][j]+sum<=k)
{
sum+=d[now][j];
now=f[now][j];
}
v[now]=true;
}
else//能到达根节点
{
t[++use_sum].left=k-e[army[i]].dis;
t[use_sum].bl=e[army[i]].bl;
}
}
dfs();
for(int i=front[];i;i=nextt[i])
if(!v[to[i]])
{
g[++point_sum].dis=val[i];
g[point_sum].id=to[i];
}
if(use_sum<point_sum) return false;
sort(t+,t+use_sum+,cmp1);
sort(g+,g+point_sum+,cmp2);
int j=;
for(int i=;i<=use_sum;i++)
{
if(!v[t[i].bl]) v[t[i].bl]=true;
else if(t[i].left>=g[j].dis) v[g[j].id]=true;
while(j<=point_sum&&v[g[j].id]) j++;
}
return j>point_sum;
}
void pre()
{
bfs();
for(int i=;i<=p;i++)//倍增预处理
for(int j=;j<=n;j++)
{
f[j][i]=f[f[j][i-]][i-];
d[j][i]=f[j][i] ? d[j][i-]+d[f[j][i-]][i-]:;
}
}
int main()
{
freopen("blockade.in","r",stdin);
freopen("blockade.out","w",stdout);
scanf("%d",&n);
p=int(log(n)/log()+);
int u,v,w;
for(int i=;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
r+=w;
}
scanf("%d",&m);
for(int i=;i<=m;i++) scanf("%d",&army[i]);
pre();
bool ok=false;
while(l<=r)
{
mid=l+r>>;
if(check(mid)) {ok=true;ans=mid;r=mid-;}
else l=mid+;
}
if(!ok) printf("-1");
else printf("%lld",ans);
}
1、在洛谷提交的时候最后一个点TLE,在二分判断里去了一个没用的O(m)的循环
然后A了
所以勿要轻视小的优化,尤其在一个多次调用的函数中
2、考试时又读错题了,没注意到一个军队只能建一个检查点
不,应该注意到了,没上心
最近老读错题,眼不下字
自己做时的思路误区:
1、判断根节点的哪些孩子需要移动军队的时候,直接枚举根节点的孩子
错误
原因:若点i的所有孩子都不需要军队移动,那么i也不需要军队移动,所以要递归判断
2、若军队i一开始在城市j,那军队i就在城市j建立检查点,反正不花时间移动
错误
原因2条 ① 同1 ②可能多个军队开始在一个城市
3、若军队i从点根节点的孩子j到达根节点,且j需要军队去建检查点,那么军队i就在j建检查点
错误
原因如图:
显然2号城市虽然有军队,但若这支军队去3号结点建检查站,会使时间更少
NOIP2012 提高组 Day 2的更多相关文章
- 刷题总结——疫情控制(NOIP2012提高组)
题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...
- GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】
国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- NOIP2012 提高组 Day 1
期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...
- [NOIP2012] 提高组 洛谷P1084 疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...
- [NOIP2012] 提高组 洛谷P1080 国王游戏
题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...
- [NOIP2012] 提高组 洛谷P1083 借教室
题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然 ...
- [NOIP2012] 提高组 洛谷P1082 同余方程
题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输出只有一行,包含一个正 ...
- [NOIP2012] 提高组 洛谷P1079 Vigenère 密码
题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南 ...
- [NOIP2012提高组] CODEVS 1200 同余方程(扩展欧几里德算法)
数论题..所有数论对我来说都很恶心..不想再说什么了.. ------------------------------------------------ #include<iostream&g ...
随机推荐
- [SHOI2012]随机树
[SHOI2012]随机树 题目大意( 网址戳我! ) 随机树是一颗完全二叉树,初始状态下只有一个节点. 随机树的生成如下:每次随机选择一个叶子节点,扩展出两个儿子. 现在给定一个正整数\(n\)(\ ...
- JAVA面试题二
JAVA 综合面试题 2007-08-12 目录 Java面试题整理 9 Java面向对象 9 1. super()与this()的区别? 9 2. 作用域public,protected,priva ...
- VS中,Ctrl+Shift+F无法在文件中查找
可能是和搜狗的繁简字切换的快捷键冲突了,把搜狗的该快捷键修改或者关闭掉即可.
- angular路由详解四(子路由)
子路由是相对路由 路由配置部分: 主要是children const routes: Routes = [ {path:'home', component: HomeComponent, childr ...
- 【python学习笔记】2.列表和元组
# 第二章:列表和元组 序列中,每个元素都有个一个序号,序号以0开始,最后一个元素序号为-1,倒数第二个-2 序列类型包括,列表,元组,字符串,unicode字符串,buffer, xrange ...
- 【前端单元测试入门04】Karma
Karma 官方介绍 A simple tool that allows you to execute JavaScript code in multiple real browsers. 即一个允许 ...
- 智能合约语言 Solidity 教程系列7 - 以太单位及时间单位
这是Solidity教程系列文章第7篇介绍以太单位及时间单位,系列带你全面深入理解Solidity语言. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所 ...
- three.js 实现全景以及优化(1)
实现一个三维全景; 然后思考优化问题; 于是我问了下webgl技术交流群朋友有啥解决方案; 对于krpano.js 的了解,只是知道百度全景用了这个技术; 最后还是选择了群友给出的three.js ...
- 使用angular-ui-router替代ng-router
angular框架自身提供的ng-route在一定程度上满足了我们的需求,但是他只针对于单视图,比如点击一个link跳转到另一个视图,但是在实际业务中,需要一个状态对应的视图中还包含其他的视图,或者一 ...
- 笔记:Maven 插件配置 - maven-jar-plugin
在项目中内部重用某个模块的测试代码很常见的需求,可能某个底层模块的测试代码中包含一些常用的测试工具类,或者一些高质量的测试基类供继承,这个时候Maven用户就需要通过配置此插件将测试类打包,插件配置代 ...