而原来的细棍(加热前的细棍)就是以此弧所对的弦,你以往亟待运用那N种颜料

【SInGuLaRiTy-1025】
Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved.

【SinGuLaRiTy-1024】
Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

[POJ 1905] 棍的暴涨 (Expanding Rods)

[POJ 2709] 颜料 (Painter)

标题叙述

已知一根长为L的细棍被加热了n摄氏度,那么其新的尺寸为L’=(1+n*C)*L。中间的C是热膨胀周到。
当一根细棍被夹在两面墙中间然后被加热,它会暴涨,其形制会成为1个弧,而原本的细棍(加热前的细棍)就是其一弧所对的弦。
你的天职是一个钱打二17个结出弧的主题与弦的核心的偏离。

图片 1

标题叙述

商城出售一种由N(3<=N<=12)种差异颜色的水彩,逐个一瓶(50ML),组成的颜料套装。你以往内需动用那N种颜料;不但如此,你还索要一定数额的土灰颜料。杂货店向来不出售浅莲灰颜料——相当于它不属于这N种之一。幸运的是,青古铜色颜料是相比较好布局的,即使你取出三种差异颜色的颜料各x ml,混合起来就可以取得x ml的金红颜料(注意不是3x)。

今日,你明白各种颜料各需求多少ml。你说了算买尽大概少的“颜料套装”,来满意你须求的那N+1种颜色。那么您最少需求买多少个套装呢?

输入

饱含多组数据(每组占一行)。每一行包蕴三个非负数:细棍的尺寸,温度的变化值和细棍材质的热膨胀周密C。输入数据保险细棍不会暴涨领先本人的54%。
输入数据以多少个延续的-1终极。

输入

输入包罗若干组测试数据。每组数据一行:第1个数N,
3<=N<=12, 含义如上;接下去N+三个数,分别表示你须求的N+1种颜色的毫升数。最后一种是黄色。所有输入的毫升数<=一千.

在意:输入中不存在逐个颜料套装的毫升数。由题意可见,各种各50ml,即总括50N ml。

输出

对于每一组数据,输出总括的偏离,答案保留3位小数。

输出

对于每一组数据,输出壹个平头,表示最少套数。

样例数据

样例输入 样例输出
1000 100 0.0001
15000 10 0.00006
10 0 0.001
-1 -1 -1
61.329
225.020
0.000

 

 

 

 

 

样例数据

样例输入 样例输出
3 40 95 21 0
7 25 60 400 250 0 60 0 500
4 90 95 75 95 10
4 90 95 75 95 11
5 0 0 0 0 0 333
0
2
8
2
3
4

 

 

 

 

 

 

解析

直白二分中度,通过中度和弦长推出半径,再算角度,最终与事实上的弧长进行相比,并最后举办调整。

那种算法的裨益有以下几点;
1.接纳相交弦定理,求出半径
2,只在求sita时采纳了一回反三角函数,不像其他的算法,反复的求三角正弦,余弦啊各类·····尽量保留了精度。
3,突破以后的二分情势,并不求关于高度的calcu表明式,而是直接利用,以咬定大小
4,末了,作者认为最神奇的是大神在纷纭的题意下,找到了3个丰硕简短的单挑函数:依题长度伸张做多可是半数,相当于其形成的扇形组最大而是是半圆,那么在弦长一定的时候,给一个弧高就足以确定1个圆,进而可以规定那段弧长。

<Matchperson的剖析写的很棒,那里粘一下>

一道独立的二分难题,大家会想到直接二分答案dis,然后就足以测算出这几个弧所在的圆的半径,紧接着就能够求出弧长。用求出的弧长与真的的弧长做相比来确定下一遍二分的限定。

不过有个问题,怎么保障算出的弧长满意单调性?能够yy一下拿到。
1.dis小的时候:
图片 2
2.dis大的时候:
图片 3

在木棍原长度不变的情事下,dis越大,明显木棍越膨胀,所以弧长也就越大,知足单调性。

满足了单调性之后,大家就可以安心二分了,那里再详尽说贝因美(Beingmate)(Beingmate)下怎样求弧长:
图片 4
依据勾股定理,大家领略(昂科雷-dis)^2+(len/2)^2=ENVISION^2,所以:
R^2-2*R*dis+dis^2+len^2/4=R^2
2*R*dis=dis^2+len^2/4
R=(dis+len^2/4/dis)/2
根据len’=2*θ*R=2*acos((R-dis)/R)*途观(acos表示反三角函数,即知道cos值求角度(弧度制)),就足以拿走弧长。
二分的界定:弧最多是半圆,所以dis最多是len/2。

奇异:当len=0或n=0或C=0时,答案就是0,最好特判掉。否则大概会招致被0除错误。

解析

样例的前四组数据,都很简短,直接找最大,然后模拟就足以,没什么好说的。但对于第五组数据,就有点坑了。我们会发觉:如若依据正规解法两次50ml地配品蓝颜料,答案昭昭不是4.之所以,在那里我们要1ml、1ml地配,直到配满栗褐的终止。

Code

#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

#define eps 1e-4

double l,c,ls,n,r,sita;

double solve(double a,double b)
{
    double left,right,mid;
    left=a;
    right=b;
    while(left+eps<right)
    {

        mid=(left+right)/2;
        r=l*l/8/mid+mid/2;
        sita=2*asin(l/2/r);
        if(sita*r>=ls)
            right=mid;
        else
            left=mid;
    }
    return left;
}

int main()
{
    while(~scanf("%lf%lf%lf",&l,&n,&c))
    {
        if(l<0||n<0||c<0)break;
        ls=l*(1+n*c);
        printf("%.3f\n",solve(0,l/2));
    }
    return 0;
}

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=15;
int a[maxn],b[maxn];
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    int n,m,k;
    while(scanf("%d",&n)&&n)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        sort(a,a+n);
        if(a[n-1]%50==0) k=a[n-1]/50;
        else k=a[n-1]/50+1;
        int t=0;
        for(int i=0;i<n;i++)
            b[i]=k*50-a[i];
        while(t<m)
        {
            if(b[2]==0)
            {
                k+=1;
                for(int i=0;i<n;i++)
                    b[i]+=50;
            }
            else
            {
                t++;
                b[0]--,b[1]--,b[2]--;
                sort(b,b+n,cmp);
            }
        }
        cout<<k<<endl;
    }
    return 0;
}

[POJ 1836] 士兵站队 (Alignment)

[POJ 2393] 益生菌创造厂 (Yogurt Factory)

题材叙述

在阵容中,二个团是由士兵组成的。在早晨的检阅中,士兵们在首长面前站成一行。但总监对士兵们的行列并不顺心。士兵们真的依照他们的编号由小到大站成一列,但并不是按高度顺序来站的。于是,长官让有个别士兵出列,其余留在队里大巴兵没有互换地方,变成了更短的一列。这么些队列满足一下标准:队伍容貌里的每贰个战斗员都至少可以望见任何部队的最前沿或最终方,(要是3个精兵要见到军队的最前沿或最终方,那么在他的火线或后方,都尚未比她高的人)。

近年来按顺序给出三个队列里的各样士兵的身高,总结出若要形成满意上述标准的行列,长官至少须求让有个别士兵出列。

题材叙述

职分规定,1个冠益乳创造厂,在N (1
<= N <= 10,000) 个礼拜内,分别要向外提供Y[i] (0 <= Y_i <=
10,000)单位的益生菌。已知那几个创设厂第i周创制每单位酸酸乳的花销为C[i] (1
<= C_i <= 5,000),储存室储存每1单位冠益乳1礼拜的支出为S (1 <= S
<= 100) 。问要成功那几个职责的蝇头开销是有点。

输入

输入数据的首先行,包罗五个整数n,表示原队列里士兵的数额。第二行,包蕴n个浮点数(最多有5个人小数),第i个浮点数表示队列中编号为i的新兵的身高hi。

中间:2 <= n
<= 一千 ,且身高hi的取值范围[0.5,2.5]。

输入

首先行:三个整数N和S

第2~n+1行:第i+1行包罗八个整数C[i]和Y[i]

输出

饱含壹个平头,表示须要出列的最少士兵数。

输出

贰个整数,表示满意安插的小小花费。注意:那一个数恐怕会超越三拾贰位整型。

样例数据

样例输入 样例输出
8
1.86 1.86 1.30621 2 1.4 1 1.97 2.2
4

 

 

 

 

样例数据

样例输入 样例输出
4 5
88 200
89 400
97 300
91 500
126900

 

 

 

 

 

解析

那道题嘛,就是让队列里最少的老板出列,使队列变成那样三个规范,如图-1。由于须要最少出列人数,也等于保存最三个人口,于是那道题就有了求最长回升子体系的DP做法。对第i私有,总结1~i的最长回升种类(长度为l)与i+1~n的最长降低系列(长度为d),对持有的i,取l+d的最大值max。答案即为n-max。二分+枚举也可求解。

图片 5

 

                                             图-1

解析

贪婪。对于每七日的订单,维护最小开销:min_cost=min(C[i],min_cost+S)。

Code

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

int n;

double num[1111];
double up[1111];
double down[1111];

const int inf=(1<<31)-1;

int b1(double ss,int Left,int Right)
{
    int L=Left;int R=Right;
    int mid;
    while(L<R)
    {
        mid=(L+R)>>1;
        if(up[mid]>ss)
        {
            R=mid;
            mid=(L+R)>>1;
        }
        else if(up[mid]==ss)
        {
            return mid;
        }
        else
        {
            L=mid+1;
            mid=(L+R)>>1;
        }
    }
    return R;
}

int b2(double ss,int Left,int Right)
{
    int L=Left;int R=Right;
    int mid;
    while(L<R)
    {
        mid=(L+R)>>1;
        if(down[mid]<ss)
        {
            R=mid;
            mid=(L+R)>>1;
        }
        else if(down[mid]==ss)
        {
            return mid;
        }
        else
        {
            L=mid+1;
            mid=(L+R)>>1;
        }
    }
    return R;
}

int main()
{
    int ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lf",&num[i]);
    for(int i=1;i<=n;i++)
    {
        memset(up,0,sizeof(up));
        memset(down,0,sizeof(down));
        int lisnum=1;
        up[0]=-1;
        for(int j=1;j<=i;j++)
        {
            int index=b1(num[j],0,lisnum);
            if(index==lisnum)
                lisnum++;
            up[index]=num[j];
        }

        int ldsnum=1;
        down[0]=inf;
        for(int j=i+1;j<=n;j++)
        {
            int index=b2(num[j],0,ldsnum);
            if(index==ldsnum)
                ldsnum++;
            down[index]=num[j];
        }
        lisnum--;ldsnum--;
        ans=max(ans,lisnum+ldsnum);
    }
    printf("%d\n",n-ans);
}

Code

#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<iostream>

#define LL long long
#define MAXN 10010
#define INF 0x3f3f3f3f

using namespace std;

LL C[MAXN];
LL Y[MAXN];
LL cost;

int main()
{
    int MAX=INF;
    int N,S;
    scanf("%d%d",&N,&S);
    for(int i=1;i<=N;i++)
    {
        cin>>C[i]>>Y[i];
        if(C[i]>MAX+S)
            C[i]=MAX+S;
        MAX=C[i];
        cost+=C[i]*Y[i];
    }
    cout<<cost;
    return 0;
}

[POJ 3714] 突袭 (Raid)

[POJ 1877] 淹没 (Flooded!)

题材叙述

给出A、B七个点集,逐个集合包括N个点。现必要分别从多个点集中取出3个点,使这五个点的离开最小。

标题叙述

将三个区域分成r*c个方块,各个方块有有2个海拔(可正可负)。求当给区域注入指定体积的水时,水面的海拔是稍微,以及被水淹没的四方占总方块数的比例。每种方块的面积为100m^2,水的体积单位为立方米。 

输入

输入的首先行蕴涵三个整数T,表示样例个数。
接下去有T个样例,每个样例的率先行事一个整数N
(1 ≤ N ≤ 100,000),表示每一个组的点的个数
继之有N行,每行有七个整数X
(0 ≤ X ≤ 1,000,000,000) and Y (0 ≤ Y ≤
1,000,000,000),代表A组的各点的坐标。
再接着N行,每行有多少个整数X
(0 ≤ X ≤ 1,000,000,000) and Y (0 ≤ Y ≤
1,000,000,000),代表B组的各点的坐标。

输入

多组用例,每组用例第一行事八个整数r和c表示区域行列数,然后是五个r*c的矩阵,矩阵成分为对应区域方块的海拔,最终是流入水的体量,以r=c=0截至输入 

输出

对此各种样例,输出两点间最小的相距,保留3个人小数。注意三个点必须来自五个不等的组。

输出

对于每组用例,输出注入水后水面的海拔以及被水淹没方块占总方块数的百分比 

样例数据

样例输入 样例输出
2
4
0 5
0 0
1 0
1 1
2 2
2 3
3 2
4 4
4
0 0
1 0
0 1
0 0
0 0
1 0
0 1
0 0
1.414
0.000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

样例数据

样例输入 样例输出
3 3
25 37 45
51 12 34
94 83 27
10000
0 0
Region 1
Water level is 46.67 meters.
66.67 percent of the region is under water.

 

 

 

 

 

 

解析

无集合限制的求近来点对:
对所有点先按x坐标不减排序,对x进行二分,拿到点集S1,点集S2,通过递归求得S1,S2的蝇头点对相差d1,d2;D=min{d1,d2};合并S1,S2:找到在S1,S2划分线左右离开为D的所有点,按y不减(不增也得以)排序;循环每一个点找它背后四个点的很小距离;最后即求得最小点对相差。
那道题有汇聚限制嘛,把同一集合之间点的距离定为无穷大就行了。

解析

(Tips:
若是在POJ上直接莫名TLE,WA,RE,提议把暗许语言的G++换成C++,玄学……)

来看那道题,首先要清楚这一个r*c的区域和矩阵一点关联都没有,于是毅然改成一列的一维数组。此时又发现体量并不佳算,于是来多少个sort,此时的区域就改成了如图-1所示的旗帜。将来,难题就相比较简单了:对于每一组数据,大家只必要判定水面从左到右延伸到了哪二个地方就能断定覆盖方块数了(在每三个岗位都有1个容量范围)。而对此体积,运用小学的体量公式也就搞出来了。(注意浮点数精度误差)

图片 6

               
                      图-1

Code

#include<cstdio>
#include<algorithm>
#include<cmath>

#define INF 1<<30

using namespace std;

long long x[200010],y[200010];
int orderx[200010],ordery[200010],n;
double solve(int start,int end);

bool cmpx(int i,int j)
{
    if(x[i]<x[j])
        return 1;
    else 
        return 0;
}

bool cmpy(int i,int j)
{
    if(y[i]<y[j])
        return 1;
    else 
        return 0;
}

double disx(int i,int j)
{
    if(orderx[i]<n&&orderx[i]<n)
          return INF;
    else if(orderx[i]>=n&&orderx[i]>=n)
          return INF;
    else
      return sqrt((double)((x[orderx[i]]-x[orderx[j]])*(x[orderx[i]]-x[orderx[j]])+(y[orderx[i]]-y[orderx[j]])*(y[orderx[i]]-y[orderx[j]])));
}

double disy(int i,int j)
{
    if(ordery[i]<n&&ordery[j]<n)
              return INF;
    else if(ordery[i]>=n&&ordery[j]>=n)
              return INF;
    else
          return sqrt((double)((x[ordery[i]]-x[ordery[j]])*(x[ordery[i]]-x[ordery[j]])+(y[ordery[i]]-y[ordery[j]])*(y[ordery[i]]-y[ordery[j]])));
}

double min(double a,double b){return a>b?b:a;}

double min(double a,double b,double c)
{
    return min(a,min(b,c));
}

int main()
{
    int T,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=0;i<2*n;i++)
        {
            scanf("%d%d",x+i,y+i);
            orderx[i]=ordery[i]=i;
        }
        sort(orderx,orderx+2*n,cmpx);
        printf("%.3lf\n",solve(0,2*n-1));
    }
    return 0;
}


double solve(int start,int end)
{
    if(start+1==end)
       return disx(start,end);
    else if(start+2==end)
       return min(disx(start,start+1),disx(start,start+2),disx(start+1,start+2));
    else
    {
        int mid=start+(end-start)/2;
        double d=min(solve(start,mid),solve(mid+1,end));
        int t=0;
        for(int i=start;i<=end;i++)
           if(fabs((double)x[orderx[i]]-(double)x[orderx[mid]])<=d)
                    ordery[t++]=orderx[i];
        sort(ordery,ordery+t,cmpy);
        for(int i=0;i<t;i++)
           for(int j=i+1;j<min(end,i+6);j++)
                    d=min(d,disy(i,j));
        return d;
    }
}

Code

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

int n,m,T;
int i;
double v;
double land[1000];

int main()
{
    T=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(m==0&&n==0)
            return 0;
        for(i=0;i<n*m;i++)
            cin>>land[i];
        cin>>v;
        sort(land,land+n*m);
        for(i=0;i<n*m-1;i++)
        {
            if(v<(land[i+1]-land[i])*(i+1)*100)
                break;
            v-=(land[i+1]-land[i])*(i+1)*100;
        }
        double h=land[i]+v/(i+1)/100;
        if(v==0)
            h=1;
        printf("Region %d\n",T++);
        printf("Water level is %.2f meters.\n",h);
        printf("%.2f percent of the region is under water.\n",(i+1)/((double)(n*m))*100);
        printf("\n");
    }
    return 0;
}

[POJ 3122] 分馅饼 (Pie)

[POJ 1328] 雷达安装 (Radar Installation)

题材叙述

本身过生日请了F个对象来插足本身的八字party。总共有N个馅饼,要把它们平均分给各种人(包含本人),并且各种人不得不从一块馅饼得到协调的那一份,并且分得的馅饼大小要平等,形状可以分裂,每块馅饼都以圆柱,中度一样。

难题叙述

我们假设海岸是无限延伸的直线,陆地在海岸的一边,大海在另一边。每个小岛是一个点位于大海那一片区域。详见图片;

每一个雷达的安装位置只能够在海岸线上,只能够覆盖半径为 d 的圆形区域。所以,如果小岛与雷达距离小于等于d才能够覆盖。

我们可以用笛卡尔积坐标系,定义海岸线是 x轴,大海在x 上方,陆地在x 轴下方,给你每个小岛在大海中的位置,并且给出雷达的覆盖范围 d ,你的任务是写一个程序,找到最少需要安装的雷达数量且能够覆盖所有的小岛。一个位置表示(x,y)坐标。

图片 7

     Figure A
Sample Input of Radar Installations

输入

第1行:一个正整数,表示测试数据的组数。
在每一组数据中:第1行蕴涵五个整数,N和F
(1 ≤ N, F ≤ 10 000);第2行包罗N个整数,表示每一个馅饼的半径。

输入

输入是多组语句输入;

每行包含两个数 n 和 d:``n 代表小岛的数量,d 代表雷达的覆盖半径;

接下来n行是小岛的位置,用一个二维坐标来表示Xi,Yi;

当输入的 n 和 d 都为0,程序结束。

输出

对此每一组数据,输出只怕的最大容积。需求误差小于10^(-3),即至长史留2人小数。

输出

对于每组数据输出一个答案,每个答案占一行,输出最小需要的雷达数量,如果不能够满足要求,则输出 -1。

样例数据

样例输入 样例输出
3
3 3
4 3 3
1 24
5
10 5
1 4 2 3 4 5 6 5 4 2
25.1327
3.1416
50.2655

 

 

 

 

 

 

 

样例数据

样例输入 样例输出
3 2
1 2
-3 1
2 1
  
1 2
0 2
  
0 0 
Case 1: 2
Case 2: 1

 

 

 

 

 

 

 

 

解析

贪欲的构思+二分。复杂度为O(nlogM),M为初叶时的high-low。开端状态,上界high为种种人分得奶酪的体积sum,下界low
= 0(恐怕是不大块的奶酪)。然后二分,每一次的mid值为(low+high)/
2,然后根据mid值(猜想值)遍历n块奶酪,看看这几个mid值能分给几个人,倘若份数大于等于f,表示mid偏小,low
= mid,反之high = mid。

只顾:那里的圆周率pi应该尽可能精确,否则简单被卡精度。

解析

先是,我们将小岛从左到右(x坐标从小到大)举行排序。接下来,大家走一回循环,总括出能掩盖第i个岛礁的雷达的坐标范围
[ll[1],rr[1]] (相当于是x轴上的线条)
,如图-2。接下来,大家从左到右再走一遍巡回,这四遍,大家看这个一段段线段有些许重合区域(那意味着某些小岛可共用三个雷达),最终计算,求出答案。

图片 8

               
             图-2

Code

#include<cstdio>
#include<cmath>

double pi=acos(-1.0);
double sum,mid,le,ri,b[10000+11],max0;

int n,f,r;

double fl(double x)
{
    int su=0;
    for(int i=0;i<n;i++)
    {
        su+=(int)(b[i]/x);
    }
    return su;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        sum=0;
        scanf("%d %d",&n,&f);
        f++;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&r);
            b[i]=r*r*pi;
            sum+=b[i];
        }
        sum=sum/f;
        le=0.0;
        ri=sum;
        while(fabs(ri-le)>1e-6)
        {
            mid=(le+ri)/2;
            if(fl(mid)>=f)
            {
                le=mid;
            }
            else
            {
                ri=mid;
            }
        }
        printf("%.4f\n",le);
    }
}

Code

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
double x[10000],y[10000],ll[11000],rr[10000];
int main()
{
    int n,d;
    int cnt=1;
    while(cin>>n>>d)
    {
        if(n==0&&d==0)
            break;
        int flag=1,sum=1;
        for(int i=0;i<n;i++)
        {
            cin>>x[i]>>y[i];
            if(y[i]>d)
                flag=0;
        }
        cout<<"Case "<<cnt;
        cnt++;
        if(flag==0||d==0)
        {
            cout<<": -1"<<endl;
            continue;
        }
        int t;
        for(int i=0;i<n-1;i++)
        {
            for(int j=0;j<n-i-1;j++)
            {
                if(x[j]>x[j+1])
                {
                    t=x[j];
                    x[j]=x[j+1];
                    x[j+1]=t;
                    t=y[j];
                    y[j]=y[j+1];
                    y[j+1]=t;
                }
            }
        }
        for (int i=0;i<n;i++)
        {
            double s=sqrt(d*d-y[i]*y[i]);
            ll[i]=x[i]-s;
            rr[i]=x[i]+s;
        }
        double x=rr[0];
        for(int i=1;i<n;i++)
        {
            if(ll[i]>x)
            {
                x=rr[i];
                sum++;
            }
            if(rr[i]<x)
            {
                x=rr[i];
            }
        }
        cout<<": "<<sum<<endl;
    }
    return 0;
}

[POJ 2366] 总和的圣礼 (Sacrament of the sum)

[POJ 1018] 通讯系统 (Communication System)

题材叙述

在此之前,有一对心思破裂的男人。为了拯救他们中间的情愫,兄弟五个人各个人都准备了部分对于他们的话可以挽救他们之间感情的数字,这么些数字可以挽救他们的真情实意吗?(若在三个列表中的分别设有1个数,它们的和为一千0,则大家认为那几个数字可以挽救他们之间的情愫)。你的程序应该控制,是或不是有大概从八个整数列表选拔那样三个数字,来救援他们的真情实意。

标题叙述

Pizoor
Communications
Inc.要建立一套通讯系统,该通讯系统必要n种设备,而每个设备分别可以有m一,m二,m三,…、mn个厂家提供生产,而种种厂家生产的同种设备都会设有八个地点的不一样:带宽bandwidths
和 价格prices。

后天各个设备都各必要二个,考虑到性价比难题,需要所采取出来的n件设备,要使得B/P最大。其中B为那n件设备的带宽的小小值,P为这n件设备的总价。

输入

每堆数(共2堆)的输入格式如下:每堆数的率先行,包罗3个平头N
( 1 <= N <= 50,000
),表示方今列表中的数字的个数;接下去N行,每一行包含贰个整数A (
-32767<= A <=32767
)。输入数据保险:第一堆数根据升序排列,第二堆数依据降序排列。

输入

第一行包括1个整数t (1
≤ t ≤ 10),表示有t组数据。

每组数据的第一行包括1个平头n (1
≤ n ≤ 100),表示所需的配备项目数。接下来有n行,其中第i (1 ≤ i ≤
n)行的第二个整数mi (1 ≤ mi ≤
100)表示生产第i种装备的厂家数量,接下去在同一行有两两成对的整数,第三个代表带宽,第二个代表标价。

输出

比方能找到符合须要的多少个数,就输出”YES”,否则输出”NO”

输出

出口对于每一组数据而言的B/P的最大值,保留3人小数。

样例数据

样例输入 样例输出
4
-175
19
19
10424
3
8951
-424
-788
YES

 

 

 

 

 

 

 

 

样例数据

样例输入 样例输出
1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110
0.649

 

 

 

 

 

解析

出于多少个数列都稳如五台山(连sort都毫不),直接对3个列表举行枚举,对另2个列表举办二分查找就行了。

解析

理所当然听大人说那道题是一道DP题,但考虑到那是贪心复习,照旧用贪心+剪枝吧。

从很小带宽初步枚举,用贪心法选出带宽大于等于最小带宽的最低价位;然后再相比较创新最大的(B/P)的值,直到抵达最大带宽;如果从带宽枚举上去,一定符合需要。

Code

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>

using namespace std;

int A[50000],B[50000];

int main()
{
    int n1,n2,mid,Max,Min;
    scanf("%d",&n1);
    for(int i=0;i<n1;++i)
        scanf("%d",&A[i]);
    scanf("%d",&n2);
    for(int i=0;i<n2;++i)
        scanf("%d",&B[i]);
    for(int i=0;i<n1;++i)
        for(Min=0,Max=n2-1,mid=(Max+Min)/2;Min<=Max;mid=(Max+Min)/2)
        {
            if(A[i]+B[mid]==10000)
            {
                printf("YES");
                return 0;
            }
            else if(A[i]+B[mid]>10000)
                Min=mid+1;
            else
                Max=mid-1;
        }
    printf("NO");
    return 0;
}

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>

using namespace std;

const int Max=101;

struct node
{
    double b;
    double p;
};
node a[Max][Max];

double b[Max*Max];
int m[Max];
int bsize;

int cmp(const void *a,const void *b)
{
    return (*(double *)a)-(*(double *)b);
}

int main()
{
    int t,n;
    cin>>t;
    while (t--)
    {
        memset(a,0,sizeof(a));
        memset(m,0,sizeof(m));
        cin>>n;
        int i,j,k;
        int bsize=0;
        for (i=0;i<n;i++)
        {
            cin>>m[i];
            for (j=0;j<m[i];j++)
            {
                cin>>a[i][j].b>>a[i][j].p;
                b[bsize++]=a[i][j].b;
            }
        }
        qsort(b,bsize,sizeof(b[0]),cmp);
        double mmax=0;
        double mmin;
        double sump=0;
        double temp=0;
        for (i=0;i<=bsize-1;i++)
        {
            sump=0;
            int changFlag = 0;
            for (j=0;j<n;j++)
            {
                mmin=32767;
                for (k=0;k<m[j];k++)
                {
                    if (a[j][k].b>=b[i]&&a[j][k].p<mmin)
                    {
                        mmin=a[j][k].p;
                        changFlag = 1;
                    }
                }
                sump+=mmin;
            }
            if(!changFlag)
                break;
            temp=b[i]*1.0/sump;
            if(temp>mmax)
                mmax=temp;
        }
        printf("%.3lf\n",mmax);
    }
    return 0;
}

 

[POJ 3301] 内华达之旅 (Texas Trip)

[POJ 1083] 移动桌子 (Moving Tables)

题材叙述

在与Dick一天的远足之后,哈利在祥和SUV的车门上发现了多少个想不到的小孔。而本土的维修店只出售星型的玻璃纤维修补质感。以往,大家把车门上的小孔当做位于平面上整数坐标的点,问:
至少要一块多大面积的椭圆形修补质地才能覆盖住所有的小孔?

题材叙述

ACM公司租用的楼群如下图所示:

图片 9

那层楼的双方各有200个房间。将来合营社说了算在屋子里面转移桌子。在移动进程中,有且仅有一张桌子可以在过道内。由此,ACM集团索要一种高效的部署来搬运桌子。已知,将一张桌子从3个屋子移到另一个屋子需求不到10分钟。由于将桌子从房间i到屋子j移动的长河中,仅需拔取过道中的i~j的片段。若三个案子的移位不联合拔取同一段过道,就足以而且展开。例如下表所示:

图片 10

对此每1个房间而言,仅有一张桌子能够被移进或移出。你的任务是写1个程序来协助计算所需的至少时间。

输入

先是行包涵一个平头T
(T ≤ 30),表示有T组测试数据。

对于每一组数据,第一行包含二个平头n
(n ≤
30),表示有n个小孔。接下来有N行,每行八个整数X和Y,分别代表2个小孔的横坐标和纵坐标。输入数据保障每2个小孔距离原点(0,0)不当先500个单位距离。

输入

输入包蕴T组数据。

对于每一组数据,第一行包罗壹个平头N
(1 <= N <=
200),表示必要活动的台子。接下来有N行,每行三个整数s和t,表示桌子从s移动到t。

输出

对此每一组数据,输出一个两位小数,表示星型材质的细小面积。

输出

对此每一组数据,输出完结移动所需的至少时间。

样例数据

样例输入 样例输出
2
4
-1 -1
1 -1
1 1
-1 1
4
10 1
10 -1
-10 1
-10 -1
4.00
242.00

 

 

 

 

 

 

 

 

 

样例数据

样例输入 样例输出
3 
4 
10 20 
30 40 
50 60 
70 80 
2 
1 3 
2 200 
3 
10 100 
20 80 
30 50 
10
20
30

 

 

 

 

 

 

 

 

 

 

 

解析

刚开始看到题,以为正方形不会旋转,算算点的分界就行了,后来才发觉:
假设圆锥形旋转起来,面积是有大概压缩的。上面是正解:
为了有利于计算,我们不让长方形旋转,而是让长方形边始终与坐标轴保持平行,让点旋转,三分点的旋转角度,范围[0,pi],每一遍旋转后总计横纵坐标最大差值
(计算边界) ,取个最大值即为当前角度对应的椭圆形边长 。

图片 11

                             图-2

解析 

只需把区间经过的地点计数,最终找到最大计数就可以了。答案的最优性表达:题意可以用区间图表示,即每2个区间为2个终极,要是多个区间范围相交,则在中间连上一条边。题目便转载为求区间图的色数,由定理:区间图中色数=团数知道求最大团的顶点数即可。那么最大团的终极数就是上述思路。[最大团是怎么?]

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

#define eps 1e-12
#define pi acos(-1.0)
#define maxn 33

struct node 
{
    double x,y;
    node spin(double a)
    {
        node ans;
        ans.x=x*sin(a)-y*cos(a);
        ans.y=x*cos(a)+y*sin(a);
        return ans;
    }
}a[maxn],b[maxn];

int T,n;

double cal(double x)
{
    for(int i=0;i<n;i++)b[i]=a[i].spin(x);
    double x1,x2,y1,y2;
    x1=x2=b[0].x,y1=y2=b[0].y;
    for(int i=1;i<n;i++)
        x1=min(x1,b[i].x),x2=max(x2,b[i].x),y1=min(y1,b[i].y),y2=max(y2,b[i].y);
    return max(x2-x1,y2-y1);
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%lf%lf",&a[i].x,&a[i].y);
        double l=0,r=pi,mid1,mid2,f1,f2;
        while(1)
        {
            mid1=(l+r)/2;
            mid2=(mid1+r)/2;
            f1=cal(mid1);
            f2=cal(mid2);
            if(abs(f1-f2)<eps)
                break;
            else if(f1<f2)
                r=mid2;
            else 
                l=mid1;
        }
        printf("%.2f\n",f1*f1);
    }
    return 0;
}

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

#define N 202

using namespace std;

int n,flag[N],T;

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        int a,b,res=0;
        scanf("%d",&n);
        memset(flag,0,sizeof(flag));
        for(int i=0;i<n;i++)
        {
            scanf("%d %d",&a,&b);
            if(a>b)
            {
                swap(a,b);
            }
            a=(a-1)>>1;
            b=(b-1)>>1;
            for(int j=a;j<=b;j++)
                flag[j]++;
        }
        for(int i=0;i<N;i++)
            res=max(res,flag[i]);
        printf("%d\n",res*10);
    }
    return 0;
}

[POJ 2503] 宝贝鱼翻译机 (Bablefish)

[HDU 1239] 再度呼叫地外文明(Calling Extraterrestrial 英特尔ligence Again)

标题叙述

您刚刚从滑铁卢(沃特erloo)搬到了壹个新的大城市。这里的芸芸众生都说着一种令人费解的外语方言。幸运的是,你有一本可以协理你驾驭的词典。

难题叙述

交由一个超出4的整数m和三个真分数a/b,求最佳素数对p、q,使得a/b<=p/q<=1且pq<=m。最佳即为满足条件的数对中pq最大的一对。

输入

输入包括最多100,000条词典条目,接下去有3个空行,其次是最多100,000词的本来音信。
每三个词典条目包罗用空格分开的七个字符串S1和S2,其中S1是译文,S2是原文。原始音信为多行,一行1个急需翻译的单词。
输入数据保险每3个单词的程长度不超过十一个字符。

输入

输入文件最多3000行。每一行包涵了八个整数:整数m,分子a,分母b。( 4
< m <= 一千00 and 1 <= a <= b <= 1000 且满足 0 < a / b
< 1)

以三个0结尾。

输出

对于每三个索要翻译的单词,输出翻译后的单词。若原始单词不设有在词典中,输出”eh”(不包括引号)。

输出

输出是三个由正整数数对组合的行列。表示每一组数据中的p、q。

样例数据

样例输入 样例输出
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay

atcay
ittenkay
oopslay
cat
eh
loops

 

 

 

 

 

 

 

 

样例数据

样例输入 样例输出
5 1 2
99999 999 999
1680 5 16
1970 1 1
2002 4 11
0 0 0
2 2
313 313
23 73
43 43
37 53

 

 

 

 

 

 

解析

从小到大排序,然后对于各个询问,二分查找。复杂度O(nlogn)。

解析

直接枚举查找:急迅求出素数表后,运用二分查找检查当前数是还是不是为素数。(注意,由于是求最大,所以从后往前搜,直到j<z时退出)。

还要关注p的取值范围:[1,sqrt(n)] 

Code

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

struct node
{
    char s1[20],s2[20];
}a[100005];

int len;

int cmp(node a,node b)
{
    return strcmp(a.s2,b.s2)<0;
}

int main()
{
    len=0;
    char str[50];
    while(gets(str))
    {
        if(str[0]=='\0')
            break;
        sscanf(str,"%s%s",a[len].s1,a[len].s2);
        len++;
    }
    sort(a,a+len,cmp);
    while(gets(str))
    {
        int l=0,r=len-1,mid,flag=1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(strcmp(str,a[mid].s2)==0)
            {
                printf("%s\n",a[mid].s1);
                flag=0;
                break;
            }
            else if(strcmp(str,a[mid].s2)<0)
                r=mid-1;
            else
                l=mid+1;
        }
        if(flag)
            printf("eh\n");
    }
    return 0;
}

Code

#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

int prim[100005],is[100005];
int num=0;

int Find(int v)
{
    int m;
    int l=1,h=num;
    while(l<h)
    {
        m=(l+h)/2;
        if(prim[m]==v)
            return 1;
        if(prim[m]<v)
            l=m+1;
        else
            h=m;
    }
    return 0;
}

int main()
{
    int m,a,b,Max,j,i,x,zx,zi,z;
    double t;
    int s,e=(int)(sqrt(0.0+100000)+1);
    memset(is,1,sizeof(is));
    prim[++num]=2;
    is[0]=is[1]=0;
    for(i=4;i<=100000;i+=2)
        is[i]=0;
    for(i=3;i<e;i+=2)
        if(is[i])
        {
            prim[++num]=i;
            for(s=i*2,j=i*i;j<=100000;j+=s)
                is[j]=0;
        }
    for(;i<100000;i+=2)
        if(is[i])
            prim[++num]=i;
    while(scanf("%d%d%d",&m,&a,&b)!=EOF)
    {
        z=0;
        if(m==0 && a==0 && b==0)
            break;
        t=a*1.0/b;
        for(int j=m;j>=1;j--)
        {
            if(j<z)
                break;
            Max=(int)sqrt(0.0+j);
            for(i=Max;i>=1;i--)
            {
                x=j/i;
                if(x*t<=i && x>=i)
                    if(Find(i)&&Find(x))
                        if(x*i>z)
                        {
                            zx=x;
                            zi=i;
                            z=x*i;
                        }
            }
        }
        printf("%d %d\n",zi,zx);
    }
    return 0;
}

[POJ 3737] UmBasketella (UmBasketella)

[UVA 1292] 战略游戏 (Strategic Game)

标题叙述

给定圆锥的外表积S,求那一个圆锥的最大体积V,以及此时它的高h与底面半径r。

标题叙述

Bob喜欢玩战略游戏。今后有一座都市,其里面的征途构成了一棵树。鲍伯可以在少数城市派2个战斗员守护,该士兵可以瞭望到持有与该城市不断的边。问Bob最少要选派多少个兵卒,才能把所有的边都瞭望到。

比如说,在下边那棵树中,只须要把战士放在节点1就足以瞭望到左右的边了。

图片 12

 

输入

输入数据中有五个测试点,各种测试点只包括贰个实数
S, 代表圆锥的表面积。表面积 1≤S≤10000.

输入

输入文件包蕴多组数据。
每一组数据包括了对树的以下描述:
1>
节点数N;
2>
接下来N行,每一行对二个节点进行实际讲述,其格式如下:
节点编号:(与其连续的道路数m)
连接的节点1 总是的节点2 总是的节点3 ……总是的节点m

输出

对于各种测试点,输出应该包括三行:
第一行输出最大体积V;
其次行输出高h;
其三行输出底面半径r;
负有实数应该四舍五入到0.01。

输出

对此每一组数据,输出要求的最少士兵数。

样例数据

样例输入 样例输出
30
10.93
4.37
1.55

 

 

 

 

 

样例数据

样例输入 样例输出

4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)

1
2

 

 

 

 

 

 

 

 

 

解析

枚举底面圆半径,算圆锥的容积。可以列出表达式,满意三分,因而得以三分枚举底面圆半径。

解析

最少点覆盖难点
可以用树形DP搞定,大家把无根树抽象成一棵有根树,0为树根。对于自由3个节点i来说,设dp[i][0]意味着在该节点不放士兵,dp[i][1]代表在该节点放置士兵。
那么结合他的子节点就足以获取气象转移方程
dp[i][1]=sum(dp[k][0])+1
k为i的子节点,下同,因为本节点没放,则子节点一定要放
dp[i][0]=sum(min(dp[k][0],dp[k][1]))
因为本节点放了,所以取子节点放和不放的最小值
最终答案就是min(dp[0][0],dp[0][1])

<三分查找>

Code

#include<iostream>  
#include<vector>  
#include<cstring>  
#include<cstdio>  
#include<algorithm>  
#include<cmath>  
using namespace std;  

const int maxn = 1600;  
int dp[maxn][2];  
int n;  
vector<int> tree[maxn];  

int min(int a,int b)  
{  
    return a<b?a:b;  
}  

void dfs(int fa,int now)  
{  
    dp[now][0] = 0;  
    dp[now][1] = 1;  

    int len = tree[now].size();  
    int i;  

    for(i=0;i<len;i++)  
    {  
        int t=tree[now][i];  
        if(t!=fa)  
        {  
            dfs(now,t);  
            dp[now][0] += dp[t][1];  
            dp[now][1] += min(dp[t][0],dp[t][1]);  
        }  
    }  

}  


int main()  
{  
    while(~scanf("%d",&n))  
    {  
        int i;  
        for(i=0;i<n;i++)  
        {  
            tree[i].clear();  
        }  
        for(i=0;i<n;i++)  
        {  
            int b;  
            int a;  
            int j;  
            scanf("%d:(%d)",&a,&b);  
            for(j=0;j<b;j++)  
            {  
                int x;  
                scanf("%d",&x);  
                tree[a].push_back(x);  
                tree[x].push_back(a);  
            }  
        }  
        dfs(-1,0);  
        cout<<min(dp[0][0],dp[0][1])<<endl;  
    }  
    return 0;  
}
概念

在二分物色的底蕴上,在右区间(或左区间)再举行三回二分,那样的搜索算法称为三分摸索,也等于三分法。三分查找平时用来火速确定最值。

二分查找所面向的检索行列的渴求是:具有单调性(不必然严酷单调);没有单调性的行列不是利用二分查找。

而与二分查找不一样的是,三分法所面向的探寻行列的须要是:系列为1个凸性函数(例如二次函数)。通俗来讲,就是该体系必须有二个最大值(或最小值),在最大值(最小值)的左侧体系,必须知足不严苛单调递增(递减),右边系列必须满意不严酷单调递减(递增)。如图-2,表示一个有最大值的凸性函数:

图片 13

                                          图-3

壹,与二分法类似,先取整个区间的中等值mid=(left+right)/2。

mid=(left+right)/2; 

贰,再取左边的中级值Mid-mid=(mid+right)/2。

Mid_mid=(mid+right)/2;

三,若发现mid比Mid-mid更近乎最值,我们就抛弃右区间,否则我们放任左区间。

相比较mid与Mid-mid什么人最靠近最值,只要求确定mid所在的函数值与Mid-mid所在的函数值的深浅。当最值为最大值时,mid与midmid中较大的不行自然越来越贴近最值。最值为最小值时反而。 

if(cal(mid)>cal(Mid_mid))  
    right=Mid_mid;  
else  
    left=mid;  

4、重复一,二,三,步骤,直到找到最值。

[POJ 3617] 最佳奶牛种类 (Best Cow Line)

<另一种思路>
double three_devide(double low,double up)  
{  
    double m1,m2;  
    while(up-low>=eps)  
    {  
        m1=low+(up-low)/3;  
        m2=up-(up-low)/3;  
        if(f(m1)<=f(m2))  
            low=m1;  
        else  
            up=m2;  
    }  
    return (m1+m2)/2;  
}  

 

[guognib的三分模板]

题材叙述

村民John带着他的奶牛们去出席一个交锋。奶牛们排成一列,依次取出每头奶牛名字的首字母组成队名。为了得到1个字典序最小的队名。John要重新排列奶牛队5、排列规则是那般的:他不得不将奶牛队列的队头或队尾依次参预新队列的队尾,直到所有奶牛整体加盟到新队列甘休。问她能得到的字典序最小的队名?

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

#define eps 10e-6

using namespace std;

const double pi=acos(double(-1));

double S;

double cal(double r)
{
    double R=S/pi/r-r;
    double h=sqrt(R*R-r*r);
    return h*pi*r*r/3;
}

int main()
{
    while(~scanf("%lf",&S))
    {
        double l=0,r=sqrt(S/pi);
        double m1,m2,v1,v2;
        while(l+eps<r)
        {
            m1=l+(r-l)/3;
            m2=r-(r-l)/3;
            v1=cal(m1);
            v2=cal(m2);
            if(v1<v2)l=m1;
            else r=m2;
        }
        double R=S/pi/r-r;
        double h=sqrt(R*R-r*r);
        double V=h*pi*r*r/3;
        printf("%.2f\n%.2f\n%.2f\n",V,h,r);
    }
    return 0;
}

输入

第1行包括3个整数N,表示奶牛的总数据。

第2到N+1行描述每2只奶牛。第i+1行代表在原本系列中编号为i的奶牛的首字母。

[POJ 1987] 距离统计 (Distance Statistics)

输出

字典序最小的字符串。

难点叙述

Farmer
John以后交给1个平头K (1 <= K <=
1,000,000,000),须要您总计出相隔路程不超越K的农场的对数。
(Tips:1>被统计的农场亟须是差其他七个农场;2>农场里边的路途由道路的尺寸控制)

样例数据

样例输入 样例输出
6
A
C
D
B
C
B
ABCBCD

 

 

 

 

 

 

 

输入

第1行:包括七个整数N
(2 <= N <= 40,000)和M (1 <= M <
40,000)。N表示农场数,M表示道路数。
第2~M+1行:每一行提交一条道路的新闻F1、F2(连接的五个农场)、L(道路长度,1
<= L <=
1000)、D(从F1到F2的矛头,用N、S、W、E表示,在主旨中绝非意义)
第M+2行:三个整数K。

解析

贪心不足就行。每便从上和从下接纳最小的,若相等则向中档搜索。

输出

符合必要的农场对数。

Code

#include<cstdio>
#include<cstring>
#include<iostream>

#define MAXN 2010

using namespace std;

int n,str[MAXN];

int main()
{
    scanf("%d",&n);
    char ch;
    for(int i=0;i<n;i++)
    {
        getchar();
        ch=getchar();
        str[i]=ch-'A';
    }
    int pre=0,last=n-1,Count=0;
    for(int i=0;i<n;i++)
    {
        if(str[pre]==str[last])
        {
            int pr=pre,la=last,flag=0;
            while(pr<=la)
            {
                if(str[pr]<str[la])
                {
                    printf("%c",str[pre]+'A');
                    Count++;
                    flag=1;
                    pre++;
                    break;
                }
                else if(str[pr]>str[la])
                {
                    printf("%c",str[last]+'A');
                    Count++;
                    flag=1;
                    last--;
                    break;
                }
                pr++,la--;
            }
            if(!flag)
            {
                printf("%c",str[pre]+'A');
                Count++;
                pre++;
            }
        }
        else if(str[pre]<str[last])
        {
            printf("%c",str[pre]+'A');
            Count++;
            pre++;
        }
        else
        {
            printf("%c",str[last]+'A');
            Count++;
            last--;
        }
        if(Count==80)
        {
            Count=0;
            printf("\n");
        }
    }
    if(Count)
        printf("\n");
    return 0;
}

样例数据

样例输入 样例输出
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
10
5

 

 

 

 

 

 

 

 

<样例解释>

有5对路途不超过10的农场: 1-4
(3), 4-7 (2), 1-7 (5), 3-5 (7) 和 3-6 (9)。

[POJ 3069] 萨鲁曼的军旅 (Saruman’s Army)

解析

树的点分治”裸题”。

一,把那棵无根树以1为根节点,使其成为一棵有根树。
二,对于每棵以往要处理的树,进行如下处理:
(1)遍历那棵树,找到所有1个端点为根,路径长度不当先k的门路总数
(2)通过(1)求出的结果求和,枚举+二分总括出装有长度不当先k的的途径总数
(3)去重:相当于删除(2)中总结有重叠的门路部分
(4)找到那棵子树的主心骨,递归处理那棵子树,约等于再一次步骤2
三,总括答案并出口

[没看懂树分治?]
 你还是能翻阅漆子超的国家集训队舆论《分治算法在树的不二法门难点中的应用》

难点叙述

萨鲁曼要对友好的一列军队开展监视,由此她要给予这一列军队中的部分士兵监视的职责。但每贰个监视的大兵仅能遮盖距离本身普拉多个单位以内的老董(包蕴第Tucson个)。将来,若要覆盖整支军队,至少需求多少个监视的新兵?

Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

#define MAX 40005

using namespace std;

int tot=0,ans=0;
int n,m,k,to[2*MAX],next[2*MAX],head[MAX],value[2*MAX];
int u[MAX],t,size[MAX],f[MAX],done[MAX];

struct wbysr
{
    int belong,dis;
}a[MAX];

bool cmp(wbysr a1,wbysr a2)
{
    return a1.dis<a2.dis;
}

void add(int from,int To,int weight)
{
    to[++tot]=To;
    next[tot]=head[from];
    value[tot]=weight;
    head[from]=tot;
}

void dfs(int x,int fa)
{
    u[++t]=x;
    size[x]=1;
    f[x]=0;
    for(int i=head[x];i;i=next[i])
        if(!done[to[i]]&&to[i]!=fa)
            dfs(to[i],x),size[x]+=size[to[i]],f[x]=max(f[x],size[to[i]]);
    return;
}

int find_root(int x)
{
    t=0;
    dfs(x,0);
    int Min=0x7fffffff,p;
    for(int i=1;i<=t;i++)
        if(max(size[x]-size[u[i]],f[u[i]])<=Min)
            Min=max(size[x]-size[u[i]],f[u[i]]),p=u[i];
    return p;
}

void dfs2(int x,int fa,int Belong,int dist)
{
    a[++t].belong=Belong;
    a[t].dis=dist;
    for(int i=head[x];i;i=next[i])
        if(!done[to[i]]&&to[i]!=fa)
            dfs2(to[i],x,Belong,dist+value[i]);
    return;
}

inline void calc(int x)
{
    t=0;
    a[++t].belong=x;
    a[t].dis=0;
    for(int i=head[x];i;i=next[i])
        if(!done[to[i]])
            dfs2(to[i],x,to[i],value[i]);
    sort(a+1,a+1+t,cmp);
    int r=t,same[MAX]={0};
    for(int i=1;i<=t;i++)
        same[a[i].belong]++;
    for(int l=1;l<=t;l++)
    {
        while(a[l].dis+a[r].dis>k&&r>l)
            same[a[r].belong]--,r--;
        same[a[l].belong]--;
        if(r>l)
            ans+=r-l-same[a[l].belong];
    }
}

inline void work(int x)
{
    int root=find_root(x);
    done[root]=1;
    calc(root);
    for(int i=head[root];i;i=next[i])
        if(!done[to[i]])
            work(to[i]);
    return;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a1,a2,a3;
        char ch;
        scanf("%d%d%d %c",&a1,&a2,&a3,&ch);
        add(a1,a2,a3);
        add(a2,a1,a3);
    }
    scanf("%d",&k);
    ans=0;
    work(1);
    printf("%d\n",ans);
    return 0;
}

 

Time:
2017-07-15

输入

输入包罗多组数据。每一组数据以八个整数奇骏和N初步,Odyssey (0
≤ 奇骏 ≤ 1000)表示士兵可以监视的范围,N( 1 ≤ N ≤
一千)表示这一列军队的新兵数。接下来一行包涵N个整数,表示每二个老将所处的岗位X (
1 ≤ X ≤ 一千)。当Tucson=N=-1时,输入数据截至。

输出

对此每一组数据,输出最少须要的精兵数。

样例数据

样例输入 样例输出
0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1
2
4

 

 

 

 

 

 

解析

从八个未覆盖的岗位向前遍历,找到满意距离小于
Odyssey的最左边的点,这一个点一定作为二个装置的停放地方,然后从那么些地点找到出手的细小的不能掩盖到的岗位,那么些岗位作为下三次的起源…循环下去,直到所有的点都被遮住到。

Code

#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iostream>

#define MAXN 1010

using namespace std;

int army[MAXN];

int R,N;

int main()
{
    while(scanf("%d%d",&R,&N)!=EOF)
    {
        if(R==-1&&N==-1)
            return 0;
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&army[i]);
        }
        sort(army+1,army+N+1);
        int i=1,cnt=0;
        while(i<=N)
        {
            int bg=army[i++];
            while(i<=N&&army[i]<=bg+R)
            {
                i++;
            }
            int st=army[i-1];
            while(i<=N&&army[i]<=st+R)
            {
                i++;
            }
            cnt+=1;
        }
        printf("%d\n",cnt);
        memset(army,0,sizeof(army));
    }
}

[POJ 3253] 修理篱笆 (Fence Repair)

难题叙述

Farmer
John要去做篱笆,他一起必要N块木板,也量出每块木板须求多少长度。他买了如此一整块木板,那些木板的尺寸是享有要求的木板长度之和。可是她平素不锯子。于是他找朋友去借锯子。不过朋友要收费。收费是如此的,锯开一块长度为L的木板收费L元。请问Farmer
John使用她对象的锯子,最少要花多少钱。

输入

第1行:
包罗多少个整数N (1 ≤ N ≤ 20,000) ,表示所需木板的数目。
第2到N+1行:每行三个平头,表示一块木板的长度L
(1 ≤ L ≤ 50,000)。

输出

壹个整数,表示Farmer
John最少费用的金额。

样例数据

样例输入 样例输出
3
8
5
8
34

 

 

 

 

 

 

解析

是因为要使成本最小,由此很不难明白,大家每次索要切掉最长的那些有个别,来防备那某个在前面的估算中被频仍叠加进开支中。当然,固然大家向来用sort排序的话,肯定会晚点,所以大家要用优先队列。做这道题时总有种“合并果子”的感到。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;

priority_queue<int,vector<int>,greater<int> > pq;

int main()
{
    int n(0);
    cin>>n;
    while(cin>>n)
    {
        pq.push(n);
    }
    long long sum(0);
    int l1(0),l2(0);
    while(pq.size()>1)
    {
        l1=pq.top();
        pq.pop();
        l2=pq.top();
        pq.pop();
        sum = sum+l1+l2;
        pq.push(l1+l2);
    }
    cout<<sum;
    return 0;
}

[POJ 2376] 打扫谷仓 (Cleaning Shifts)

题材叙述

老乡John让他的N头奶牛们打扫谷仓。他把一天分成T个时间段,第多个时间段为1,最终二个岁月段为T。第i头奶牛愿意从第Si个日子段工作到第Ti个时辰段。问最少要求多少奶牛,才能确保每多少个时刻段都有奶牛在工作。假如不能够担保,则输出-1.

输入

第1行:五个整数N
(1<= N <=25,000)和T (1<= T <=1,000,000)。
第2到N+1行:每一行包涵一组起来时间和完工时间,表示1头奶牛工作的年华段。

输出

出口二个平头,表示最少要求有个别头奶牛。

样例数据

样例输入 样例输出
3 10
1 7
3 6
6 10
2

 

 

 

 

 

解析

那题乍一看,不就是距离覆盖难点吗?
[CQBZOJ上的间距覆盖难点] 

先对每一个时间段(其实就是线条)按左端点由小到大进行排序,从岁月段1起始一段一段地接上来,连接时,在上下两条线段有交点的前提下使新的右端点最远,那样就能确保使用最少的线条,即奶牛数最小。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;

const int maxn = 25000 + 5;
const int maxd = 1000000 + 5;

struct Edge
{
    int x;
    int y;
}cow[maxn];

int N,T;
int X,Y;

bool cmp(Edge a,Edge b)
{
    if(a.x==b.x) return a.y>b.y;
    return a.x<b.x;
}

int main()
{
    X=0;
    Y=0;
    scanf("%d%d",&N,&T);
    for(int i=0;i<N;i++)
    {
        scanf("%d%d",&cow[i].x,&cow[i].y);
        if(cow[i].x==1)
            X=1;
        if(cow[i].y==T)
            Y=1;
    }
    sort(cow,cow+N,cmp);
    if(X==0||Y==0)
    {
        printf("-1\n");
        return 0;
    }
    int ans=1,End=0;
    int Start=cow[0].y;
    int maxy=cow[0].y;
    while(true)
    {
        while(End+1<N&&cow[End+1].x<=Start+1)
        {
            End++;
            if(cow[End].y>maxy)
            {
                maxy=cow[End].y;
            }
        }
        if(maxy!=Start)
        {
            ans++;
            Start=maxy;
        }
        else
        {
            if(End==N-1)
            {
                break;
            }
            else
            {
                printf("-1\n");
                return 0;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

[POJ 3190] 挤奶预定 (Stall Reservation)

题材叙述

有N头奶牛,(1<=N<=50,000),每头奶牛只在一定的时间段内[A,B]内才愿意挤奶(1<=A,B<=1,000,000)。三个挤奶机只可以同时挤2头奶牛。农夫约翰最少须要预备多少个挤奶机,才能满意所有奶牛的挤奶须要。

输入

第1行:一个平头N,表示奶牛数。
第2到N+1行:每一行包括多少个整数,分别代表多只奶牛愿意挤奶的起来时间和终结时间。

输出

第1行:输出所需求的挤奶机的起码数量。
第2到N+1行:第i+1行的整数表示第i头奶牛所利用的挤奶机的号子。

样例数据

样例输入 样例输出
5
1 10
2 4
3 6
5 8
4 7
4
1
2
3
2
4

 

 

 

 

 

 

<样例解释>

上面是挤奶机的时光安插表:(其余合理答案均可)

图片 14

解析

先按奶牛须要的时间伊始点进行从小到大排序,然后保安3个事先队列,里面以已经先导挤奶的奶牛的收尾时间早为优先。然后每回只需求检讨当前是还是不是有奶牛的挤奶工作早已到位的机械即可,若有,则换这台机器举行工作。若没有,则加一台新的机械。

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int maxn=50000+10;

int order[maxn];

struct Node
{
    int st,en,pos;
    friend bool operator<(Node a,Node b)
    {
       if(a.en==b.en)
        return a.st<b.st;
       return a.en>b.en;
    }
}node[maxn];

bool cmp(Node a,Node b)
{
    if(a.st==b.st)
        return a.en<b.en;
    else
        return a.st<b.st;
}

priority_queue<Node>Q;

int main()
{
    int n,ans;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&node[i].st,&node[i].en);
            node[i].pos=i;
        }
        sort(node+1,node+1+n,cmp);
        ans=1;
        Q.push(node[1]);
        order[node[1].pos]=1;
        for(int i=2;i<=n;i++)
        {
            if(!Q.empty()&&Q.top().en<node[i].st)
            {
               order[node[i].pos]=order[Q.top().pos];
               Q.pop();
            }
            else
            {
                ans++;
                order[node[i].pos]=ans;
            }
            Q.push(node[i]);
        }
        printf("%d\n",ans);
        for(int i=1;i<=n;i++)
            printf("%d\n",order[i]);
        while(!Q.empty())  Q.pop();
    }
    return 0;
}

[POJ 3040] 津贴 (Allowance)

难题叙述

用作对勤勤恳恳工作的贝茜的奖励,John已经决定开头支付贝茜贰个周周津贴。
John有N
(1≤N≤20)种币值的硬币,面值小的硬币总能整除面值较大的硬币。(比如说,币值有如下二种:1美分,5美分,10美分,50美分…)利用给定的这几个硬币,他就要周周付给贝茜一定金额的津贴C
(1 <= C <= 100,000,000)。

请帮他盘算出他最多能给贝茜发几周的津贴。

输入

第1行:一个用空格隔开的整数N和C。

第2到N+1行:每行三个整数表示一种币值的硬币.第三个整数V
(1 <= V <= 100,000,000),表示币值。

其次个整数B (1
<= B <= 1,000,000),表示约翰拥有的那种硬币的个数。

输出

二个平头,表示John付给贝茜津贴得最多的周数。

样例数据

样例输入 样例输出
3 6
10 1
1 100
5 120
111

 

 

 

 

 

解析

先导观望标题里的整除关系时,整个人是全然懵逼的:那是如何啊?后来思想也就想通了,那个原则实在就是解题的根本。

对于面值当先C的硬币自然不用说。一枚用十二日。
对此面值小于C的硬币。大家先考虑2个C的方案。要利用的周数最多我们应该就要使钱的利用率最大。也等于说损失的钱最少,尽量不要当先C太多。在不超越C的景观下对于大面值和小面值的事先接纳大面值的。因为小面值的咬合可取得大面值(整除关系)。留下小面值给末端的重组最优的只怕越大。如那种方针下没凑够C的话就找3个小小的的面额。使得组合值大于C。(使损失值最小)

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

const int INF=0x3f3f3f3f;

using namespace std;

struct node
{
    int val,mou;
}mon[25];

int n,c;
int need[25];

bool cmp(node a,node b)
{
    return a.val<b.val;
}

int main()
{
    int i,ans,ti,rest,lim,mday;
    while(~scanf("%d%d",&n,&c))
    {
        ans=0;
        lim=-1;
        for(i=0;i<n;i++)
            scanf("%d%d",&mon[i].val,&mon[i].mou);
        sort(mon,mon+n,cmp);
        for(i=n-1;i>=0;i--)
            if(mon[i].val>=c)
               ans+=mon[i].mou;
            else
            {
                lim=i;
                break;
            }
        while(1)
        {
            memset(need,0,sizeof need);
            rest=c;
            for(i=lim;i>=0;i--)
            {
                if(!mon[i].mou||!rest)
                    continue;
                ti=rest/mon[i].val;
                ti=min(ti,mon[i].mou);
                need[i]=ti;
                rest-=ti*mon[i].val;
            }
            if(rest)
            {
                for(i=0;i<=lim;i++)
                {
                    if(mon[i].val>=rest&&(mon[i].mou-need[i]))
                    {
                        need[i]++;
                        rest=0;
                        break;
                    }
                }
                if(rest)
                    break;
            }
            mday=INF;
            for(i=0;i<=lim;i++)
                if(need[i])
                mday=min(mday,mon[i].mou/need[i]);
            ans+=mday;
            for(i=0;i<=lim;i++)
                mon[i].mou-=mday*need[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

[POJ 1862] Stripies (Stripies)

标题叙述

给出N个物体,分别交付各种的质量,并且四个物体(尽管品质分别为m1,m2)相撞的时候成为一个物体,质量为2*sqrt(m1*m2),并且只会冒出多少个多个物品磕碰的处境。问最后能获取的实体的微乎其微质量是不怎么。

输入

第1行包涵一个平头N (1
<= N <= 100) 。接下来的N行,每行2个平头,表示3个实体的身分m (
1<= m <= 10,000 )。

输出

一个整数,表示小小的质量。

样例数据

样例输入 样例输出
3
72
30
50
120.000

 

 

 

 

 

解析

第一付诸贪心策略:每一次选举多个当前最大的数值举行演算,直到剩余五个物品。使用优先队列处理相比便宜。

大家得以这么表达:假如多少个物体,质量分别为
a,b,c,(a>=b>=c)。可以作证:2*sqrt(2*c*sqrt(a*b)) <=
2*sqrt(2*a*sqrt(b*c)) 。

Code

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        priority_queue<double> q;
        for(int i=0;i<n;++i)
        {
            double tp;
            cin>>tp;
            q.push(tp);
        }
        while(q.size()>1)
        {
            double a=q.top();q.pop();
            double b=q.top();q.pop();
            double tp=2*sqrt(a*b);
            q.push(tp);
        }
        printf("%.3f\n",q.top());
    }
    return 0;
}

[POJ 3262] 保养花朵 (Protecting the Flowers)

标题叙述

N (2 ≤ N ≤
100,000)头奶牛在Farmer John的庄园里吃花,将来为了保养花朵,Farmer
John要将那么些奶牛都带回牛棚里去。第i头牛离牛棚有Ti (1 ≤ Ti ≤
2,000,000)秒钟的行程, 在伺机被送回牛棚的同时,那头牛还要每分钟吃掉Di (1
≤ Di ≤ 100)朵花。而Farmer
约翰每趟只好带二头奶牛回到牛棚。

到现在,要求求出奶牛们在余下的年月里最少能吃掉多少朵花?

输入

第1行:包罗2个整数N。
第2到N+1行:每一行包括七个整数Ti和Di,分别表示奶牛回到牛棚必要的光阴和每分钟吃掉的繁花。

输出

含蓄二个平头,表示奶牛们最少吃的花朵数。

样例数据

样例输入 样例输出
6
3 1
2 5
2 3
3 2
4 1
1 6
86

 

 

 

 

 

 

 

解析

对牛进行排序,排序的规范是,假诺牛A与牛B要选三头赶走,大家率先要挑选破坏最大的二头牛赶走,留破坏小的牛。他们的毁伤着呢麽总括呢?若是先赶走牛A,那么牛B造成的损失是2×TA×DB,先赶走牛B,那么牛A造成的损失是2×TA×DB,所以,只要判断TA×DB与TA×DB哪个人大,就精通该先赶走何人了,所以数组排序的正式就是Ti×Dj>Tj×Di

Code

#include<cstdio>
#include<cstring>
#include<algorithm>

#define LL long long 
#define INF 0x3f3f3f3f

using namespace std;

struct node
{
   LL x;
   LL y;      
}a[100010];

int cmp(node n,node m)
{
   return n.y*m.x>m.y*n.x;
}

int main()
{
    int n;
    LL sum,num;
    while(scanf("%d",&n)!=EOF)
    {
        sum=0;
        memset(a,0,sizeof(a));
        for(int i=0;i<n;i++)
        {
            scanf("%I64d %I64d",&a[i].x,&a[i].y);
            sum+=a[i].y;
        }
        sort(a,a+n,cmp);
        num=0;
        for(int i=0;i<n;i++)
        {
           sum-=a[i].y;
           num+=sum*(a[i].x*2);
        }
        printf("%I64d\n",num);
    }
    return 0;
}

 

Time:
2017-07-14

 

相关文章