}
}
voidread()
{
freopen("sister.in","r",stdin);
freopen("sister.out","w",stdout);
scanf("%d",&n);
for(inti=1;i<=n;i++)
{
scanf("%d",&a[i]);
insert();
}
for(inti=1;i<=n;i++)
{
b[i]=a[1];
repair();
}
}
voidwork()
{
intnow;
while
(1)
{
now=-1;
scanf("%d",&now);
if(now==-1)break;
intl=1,r=n,m;
while(l<=r)
{
intmid=(l+r)>>1;
if(now<=b[mid])
{
r=mid-1;
m=mid;
}
else
{
l=mid+1;
m=mid;
}
}
if(now<=b[m])printf("%d\n",m);
else printf("%d\n",m+1);
}
}
intmain()
{
read();
work();
return0;
}
二分很简单,真的,不说了。
我的程序是模块化的,可读性应该还可以。
]教主的花园
【问题背景】
LHX教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障。
【问题描述】
可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(x1,y1),(x2,y2)有|x1–x2|+|y1–y2|=1,则说这两个网格是相邻的,否则不是相邻的。
教主在y=0处整条直线上的网格设置了一道屏障,即所有坐标为(x,0)的网格。
当然,他还要解决他自己与内部人员的进出问题,这样教主设置了N个入口a1,a2,…,aN可供进出,即对于y=0上的所有网格,只有(a1,0),(a2,0),……,(aN,0)可以通过,之外的所有纵坐标为0的网格均不能通过,而对于(x,y)有y不为0的网格可以认为是随意通过的。
现在教主想知道,给定M个点对(x1,y1),(x2,y2),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。
【输入格式】
输入的第1行为一个正整数N,为屏障上入口的个数。
第2行有N个整数,a1,a2,…,aN,之间用空格隔开,为这N个入口的横坐标。
第3行为一个正整数M,表示了M个询问。
接下来M行,每行4个整数x1,y1,x2,y2,有y1与y2均不等于0,表示了一个询问从(x1,y1)到(x2,y2)的最短路。
【输出格式】
输出共包含m行,第i行对于第i个询问输出从(x1,y1)到(x2,y2)的最短路距离是多少。
【样例输入】
2
2-1
2
010-1
1122
【样例输出】
4
2
【数据规模】
对于20%的数据,有n,m≤10,ai,xi,yi绝对值不超过100;
对于40%的数据,有n,m≤100,ai,xi,yi绝对值不超过1000;
对于60%的数据,有n,m≤1000,ai,xi,yi绝对值不超过100000;
对于100%的数据,有n,m≤100000,ai,xi,yi绝对值不超过100000000。
这道题我一看就知道就知道了是用二分来查找,搞不懂为什么学长们就没有一个能得到60分以上。
不多说了,这道题水。
纵坐标直接绝对值相减就是了。
如果两个点都是在纵坐标的正半轴或是负半轴,那根本不用通过路口,横座标也直接相减就是了。
如果需要跨越屏障,那么找一个a,让|x1-a|+|x2-a|最小就是了。
也就是找最近的那几个,用二分就是了。
本来刚开始还想过直接用multiset<>的,但是STL的调用时间我早就领教过了,哆嗦了一下,还是用的手打二分。
intn;
constintmaxn=100000;
inta[maxn+10];
inlineintfind1(intx)
{
intl=1,r=n,m;
while(l<=r)
{
intmid=(l+r)>>1;
if(a[mid]<=x)
{
l=mid+1;
m=mid;
}
else r=mid-1;
}
returna[m];
}
inlineintfind2(intx)
{
intl=1,r=n,m;
while(l<=r)
{
intmid=(l+r)>>1;
if(a[mid]>=x)
{
r=mid-1;
m=mid;
}
else l=mid+1;
}
returna[m];
}
inlinevoidwork()
{
intx1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1>x2)swap(x1,x2);
if((y1>0&&y2>0)||(y1<0&&y2<0))
{
printf("%d\n",abs(y2-y1)+abs(x2-x1));
return;
}
if(x1<=a[1])
{
printf("%d\n",abs(y2-y1)+abs(x1-a[1])+abs(x2-a[1]));
return;
}
if(x2>=a[n])
{
printf("%d\n",abs(y2-y1)+abs(x1-a[n])+abs(x2-a[n]));
return;
}
if(find2(x1)<=x2)
{
printf("%d\n",abs(y2-y1)+abs(x2-x1));
return;
}
inta1=find1(x1),a2=find2(x2);
intans1=abs(y1-y2)+abs(x1-a1)+abs(x2-a1),
ans2=abs(y1-y2)+abs(x1-a2)+abs(x2-a2);
printf("%d\n",min(ans1,ans2));
}
intmain()
{
freopen("p1.in","r",stdin);
freopen("p1.out","w",stdout);
scanf("%d",&n);
for(inti=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
intm;
scanf("%d",&m);
for(inti=0;i work();
fclose(stdin);
fclose(stdout);
return0;
}
软件software
【题目描述】
一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。
一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。
写一个程序,求出公司最早能在什么时候交付软件。
【输入格式】
输入文件第一行包含两个由空格隔开的整数n和m,其中1≤n≤100,1≤m≤100。
接下来的n行每行包畲两个用空格隔开的整数d1和d2:
,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中l≤d1,d2≤100。
【输出格式】
输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。
【样例】
software.in
320
11
24
16
software.out
18
【样例解释】
最快的方案是第一个技术人员完成第二个软件的18个模块,用时18天,第三个技术人员完成第一个软件的18个模块,用时18天,其余的模块由第二个技术人员完成,用时12天,做完所有模块需要18天。
如果第一个技术人员完成第二个软件的17个模块,第三个技术人员完成第一个软件的17个模块,其余的模块由第二个技术人员完成,需要用时18天,做完所有模块仍然需要18天,所以少于18天不可能做完所有模块。
这个,一开始用的是三维的动规,用f[i][j][k]表示前i个人,第一种软件生产了j个,第二种生产了k个,花的最少时间。
转移方程为:
f[i][j][k]=min(max(f[i-1][x][y],(j-x)*d1+(k-y)*d2))。
但这个方程的时间复杂度是Ο(n^5)的,只能过6组数据。
然后看题解,是先二分答案,再动规。
设当前二分的中点是mid,然后用f[i][j]表示前i个人,生产第一种软件j个,然后最多可以生产多少个第二种软件。
f[i][j]=max(f[i-1][j-k]+(mid-k*d1)/d2)。
k=min(mid/d1,j)。
二分就可以了。
把二分的右界设成0x7ffffff,也很快就过了。
这种类型的题要多留心,应该一眼就看出它是二分,这样才好。
Code:
intn,m;
constintmaxn=100;
intf[2][maxn+10],a[maxn+10],b[maxn+10];
booldp(intmid)
{
memset(f,-1,sizeof(f));
intnow=0,pas=1;
f[now][0]=0;
for(inti=0;i {
swap(pas,now);
for(intj=0;j<=m;j++)
for(intk=0;k<=min(mid/a[i],j);k++)
if(f[pas][j-k]!
=-1)
{
inttmp=(mid-k*a[i])/b[i];
f[now][j]=max(f[now][j],f[pas][j-k]+tmp);
}
}
return(f[now][m]>=m?
1:
0);
}
intmain()
{
freopen("software.in","r",stdin);
freopen("software.out","w",stdout);
scanf("%d%d",&n,&m);
for(inti=0;i scanf("%d%d",&a[i],&b[i]);
intl=0,r=0x7ffffff,ans;
while(l<=r)
{
intmid=(l+r)>>1;
if(dp(mid))
{
r=mid-1;
ans=mid;
}
else l=mid+1;
}
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return0;
}
二分/最短路]收费站cost
【题目描述】
在某个遥远的国家里,有n个城市。
编号为1,2,3,……,n。
这个国家的政府修建了m条双向的公路。
每条公路连接着两个城市。
沿着某条公路,开车从一个城市到另一个城市,需要花费一定的汽油。
开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。
所有的收费站都在城市中,在城市间的公路上没有任何的收费站。
小徐现在要开车从城市u到城市v(1<=u,v<=n)。
她的车最多可以装下s升的汽油。
在出发的时候,车的油箱是满的,并且她在路上不想加油。
在路上,每经过一个城市,她要交一定的费用。
如果她某次交的费用比较多,她的心情就会变得很糟。
所以她想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。
这个问题对于她来说太难了,于是她找到了聪明的你,你能帮帮她吗?
【输入格式】
第一行5个正整数,n,m,u,v,s。
分别表示有n个城市,m条公路,从城市u到城市v,车的油箱的容量为s升。
接下来有n行,每行1个正整数,fi。
表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。
表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,需要用ci升汽油。
【输出格式】
仅一个整数,表示小徐交费最多的一次的最小值。
如果她无法到达城市v,输出-1。
【输入样例1】
44238
8
5
6
10
212
241
134
343
【输出样例1】
8
【输入样例2】
44233
8
5
6
10
212
241
134
343
【输出样例2】
-1
【数据范围】
对于60%的数据,满足n<=200,m<=10000,s<=200
对于100%的数据,满足n<=10000,m<=50000,s<=1000000000
对于100%的数据,满足ci<=1000000000,fi<=1000000000,可能有两条边连接着相同的城市。
去年5月刚学图论时完对这道题完全没有概念,被虐得瓜兮兮的。
现在一看就知道要二分。
只是还是有一组超时了,没办法了。
二分收费,然后用spfa,凡是f[i]小于等于当前收费的,就进行松弛,然后看dis[v],如果小于等于s,即可行。
Code:
intn,m,u,v,s;
constintmaxn=10000;
structpoint
{
intx,l;
point*next;
}*p[maxn+10];
intf[maxn+10],dis[maxn+10],a[maxn+10];
boolhash[maxn+10];
intq[5000000];
voidinsert(intu,intv,intl)
{
point*now=newpoint;
now->x=v; now->l=l;
now->next=p[u]; p[u]=now;
}
voidread()
{
freopen("cost.in","r",stdin);
freopen("cost.out","w",stdout);
scanf("%d%d%d%d%d",&n,&m,&u,&v,&s);
for(inti=1;i<=n;i++)
scanf("%d",&f[i]),a[i]=f[i];
while(m--)
{
inta,b,c;
scanf("%d%d%d",&a,&b,&c);
insert(a,b,c);
insert(b,a,c);
}
sort(a+1,a+n+1);
}
boolspfa(inta)
{
memset(dis,0x3f,sizeof(dis));
memset(hash,0,sizeof(hash));
if(f[u]>a)return0;
dis[u]=0; hash[u]=1;
intl=0,r=0;
q[r++]=u;
while(l {
intx=q[l++];
hash[x]=0;
for(point*i=p[x];i;i=i->next)
if(f[i->x]<=a&&dis[i->x]>dis[x]+i->l)
{
dis[i->x]=dis[x]+i->l;
if(!
hash[i->x])
{
hash[i->x]=1;
q[r++]=i->x;
}
}
}
return(dis[v]<=s?
1:
0);
}
voidwork()
{
if(!
spfa(a[n])) printf("%d\n",-1);
else
{
intl=1,r=n,m