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 ...
随机推荐
- RabbitMQ教程C#版 - Hello World
先决条件 本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难,可以 ...
- (3)Deep Learning之神经网络和反向传播算法
往期回顾 在上一篇文章中,我们已经掌握了机器学习的基本套路,对模型.目标函数.优化算法这些概念有了一定程度的理解,而且已经会训练单个的感知器或者线性单元了.在这篇文章中,我们将把这些单独的单元按照一定 ...
- js获取本机的网络IP地址
JavaScript是一门脚本语言,是不能操作文件,读取本地信息的,所以想要获取IP,还需要借助后端技术.方法如下: //获取本机的网络ip地址 function jsonpCallback(res) ...
- C#压缩文件夹坑~
dotNet疯狂之路No.29 今天很残酷,明天更残酷,后天很美好,但是绝大部分人是死在明天晚上,只有那些真正的英雄才能见到后天的太阳. We're here to put a dent in t ...
- WordPress添加个性化的博客宠物的方法
在很多的网站上都看见过这种效果,于是自己也想试试.看见我网站上的小宠物了吗,就是这种效果. 不多说,方法如下: 工具: 下载地址:http://yunpan.cn/cFUmZB8WWthty 访问密码 ...
- Cucumber 相关资源
Cucumber support: https://cucumber.io/support yan1234abcd的专栏:http://blog.csdn.net/yan1234abcd/articl ...
- shell脚本中的整数测试
shell脚本中的整数测试 author:headsen chen 2017-10-17 13:58:12 个人原创,转载请注明作者,出处,否则依法追究法律责任 1,test用法:tes ...
- Geth 控制台使用及 Web3.js 使用实战
在开发以太坊去中心化应用,免不了和以太坊进行交互,那就离不开Web3.Geth 控制台(REPL)实现了所有的web3 API及Admin API,使用好 Geth 就是必修课.结合Geth命令用法阅 ...
- Greetings
1,Common English Greetings Hey! Hey man! Hey girl! Hi. How's it going? How are you doing? What's up? ...
- [模拟赛] T1 高级打字机
Description 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小 ...