2012 Noip提高组 Day2

时间:2023-12-29 12:47:56

1265. [NOIP2012] 同余方程

★☆   输入文件:mod.in   输出文件:mod.out   简单对比
时间限制: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。

自动选择评测机
打开 O2 优化
COGS Grader
无优化开关

提交代码 Pascal C C++

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define ll long long
ll a,b,x,y; ll exgcd(ll a,ll b){
if(b==){
x=;y=;
return a;
}
exgcd(b,a%b);
ll tmp=x;
x=y;y=tmp-(a/b)*y;
}
int main(){
freopen("mod.in","r",stdin);
freopen("mod.out","w",stdout);
scanf("%lld%lld",&a,&b);
exgcd(a,b);
while(x<)x+=b;
cout<<x;
}

1266. [NOIP2012] 借教室

★★☆   输入文件:classrooms.in   输出文件:classrooms.out   简单对比
时间限制: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。

自动选择评测机
打开 O2 优化
COGS Grader
无优化开关

提交代码 Pascal C C++

45分暴力:n^2,对每次查询进行线性区间加减
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn 1000010
#define maxm 1000010
int n,m,r[maxn],d[maxm],s[maxm],t[maxm];
int main(){
freopen("classrooms.in","r",stdin);
freopen("classrooms.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&r[i]);
for(int i=;i<=m;i++){
scanf("%d%d%d",&d[i],&s[i],&t[i]);
for(int j=s[i];j<=t[i];j++){
r[j]-=d[i];
if(r[j]<){
printf("-1\n%d",i);
return ;
}
}
}
printf("");
}

45分

100分线段树:线段树权值为区间最小值,初始为每天可用于租借的教室数量,然后区间修改,如果根节点小于0则此时换教室终止
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn 1000010
int n,m,r[maxn],opv,opx,opy,cnt;
struct node{
int l,r,v,lazy;
}tr[maxn*];
void build(int k,int l,int r){
tr[k].l=l,tr[k].r=r;
if(l==r){
scanf("%d",&tr[k].v);return;
}
int mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
tr[k].v=min(tr[k<<].v,tr[k<<|].v);
}
void down(int k){
int now=tr[k].lazy;
tr[k].lazy=;
tr[k<<].v-=now;
tr[k<<].lazy+=now;
tr[k<<|].v-=now;
tr[k<<|].lazy+=now;
}
void add(int k){
if(tr[k].l>=opx&&tr[k].r<=opy){
tr[k].v-=opv;
tr[k].lazy+=opv;
return;
}
if(tr[k].lazy)down(k);
int mid=(tr[k].l+tr[k].r)>>;
if(opx<=mid)add(k<<);
if(opy>=mid+)add(k<<|);
tr[k].v=min(tr[k<<].v,tr[k<<|].v);
}
int main(){
freopen("classrooms.in","r",stdin);
freopen("classrooms.out","w",stdout);
scanf("%d%d",&n,&m);
build(,,n);
for(int i=;i<=m;i++){
scanf("%d%d%d",&opv,&opx,&opy);
add();
if(tr[].v<){
cout<<"-1"<<endl;
cout<<i;return ;
}
}
cout<<;
return ; }

100分

1267. [NOIP2012] 疫情控制

★★★☆   输入文件:blockade.in   输出文件:blockade.out   简单对比
时间限制: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

自动选择评测机
 
打开 O2 优化
COGS Grader
无优化开关
         
提交代码 Pascal C C++

/*
二分+倍增+贪心
①题目要求使最长时间最短,那我们会想到二分答案,二分出答案之后,
要使各处的军队尽量向上跑才最优,因为这样能覆盖尽量多的点。
②对于能跑到根节点的点,我们就记录他跑到根节点后最多还能跑多远,
并且记录下他是从根节点的哪那个子节点来的,这些信息都记录到b结构体中。
③对于那些跑不到根节点的军队,我们让他待在能跑到的最高处,而且进行一遍深搜,
如果某个点的所有子节点都保证能覆盖,我们就认为它也能被覆盖。
④在根节点的子节点中找到没有被覆盖的,然后用b结构体中的军队来分配给他们,
分配原则是:如果b结构体军队原来的点没有覆盖,就覆盖原来的,否则,从小到大一一对应。
*/ #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
#define maxn 50010
int n,m,num,head[maxn*],fa[maxn][],dis[maxn][],pos[maxn];
bool vis[maxn];
struct node{
int to,v,pre;
}e[maxn*];
void Insert(int from,int to,int v){
e[++num].to=to;
e[num].v=v;
e[num].pre=head[from];
head[from]=num;
}
void dfs(int now,int father){
fa[now][]=father;
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(to==father)continue;
dis[to][]=e[i].v;
dfs(to,now);
}
} struct one{
int to,v;
}a[maxn],b[maxn];
int cmp(one x,one y){
return x.v<y.v;
}
void updata(int now){
int x=,y=;
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(to==fa[now][])continue;
updata(to);
x&=vis[to];
y=;
}
if(x&&y&&now!=)vis[now]=;
}
bool check(int x){//standard步数
memset(vis,,sizeof(vis));
int cnt=,tot=;
for(int i=;i<=m;i++){
int now=pos[i],step=;
for(int j=;j>=;j--){
if(fa[now][j]&&step+dis[now][j]<=x){
step+=dis[now][j];
now=fa[now][j];
}
}
if(now!=)vis[now]=;
else {
a[++cnt].v=x-step;
now=pos[i];
for(int j=;j>=;j--)
if(fa[now][j]>)
now=fa[now][j];
a[cnt].to=now;
}
}
updata();
for(int i=head[];i;i=e[i].pre){
if(!vis[e[i].to]){
b[++tot].to=e[i].to;
b[tot].v=e[i].v;
}
}
sort(a+,a+cnt+,cmp);
sort(b+,b+tot+,cmp);
int j=;
for(int i=;i<=cnt;i++){
if(!vis[a[i].to])vis[a[i].to]=;
else if(a[i].v>=b[j].v)vis[b[j].to]=;
while(vis[b[j].to]&&j<=tot)j++;
}
return j>tot;
}
int main(){
//freopen("Cola.txt","r",stdin);
freopen("blockade.in","r",stdin);
freopen("blockade.out","w",stdout);
int l=,r=;
scanf("%d",&n);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
Insert(x,y,z);
Insert(y,x,z);
r+=z;
}
scanf("%d",&m);
for(int i=;i<=m;i++)scanf("%d",&pos[i]);
dfs(,);
for(int i=;i<=;i++){
for(int j=;j<=n;j++){
fa[j][i]=fa[fa[j][i-]][i-];
dis[j][i]=dis[j][i-]+dis[fa[j][i-]][i-];
}
}
int ans=-;
while(l<=r){
int mid=(l+r)>>;
if(check(mid))r=mid-,ans=mid;
else l=mid+;
}
if(ans==-)printf("-1");
else printf("%d",ans);
return ;
}