[寒假集训第一场]gym101606 2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017)

3星场 难度在于英文题面太难读懂了QAQ 看样例猜题意的我

博客园的c++主题真丑

A Alien Sunset

(description)

(n)个星球,每个星球自转时间不一样,所以一天的小时数(p)也不一样,而且日出日落时间也不一样。在模(p)意义下,如果日出时间是(a)日落时间是(b),那么从(a+1)(b-1)都是白天,其他时间都是晚上。一开始所有星球时刻对齐,就是所有星球都是(0)时刻。在前(1825)天(我理解是前(182500)小时)找到一个时刻,使得每个星球都是晚上

(solution)

直接暴力模拟,时刻增加然后每个星球自己的时刻跟着走即可。只要注意它给的是模(p)意义下的日出日落时刻,就是(10)点日出(5)点日落表示白天从一天(11)点直到第二天(4)点。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n,x,l,r;
int b[1000010];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&x,&l,&r);
        if (l<r)
        {
            for (int j=0;j<=1825*100;j++)
            {
                if (j%x>l&&j%x<r)b[j]=1;
            }
        }else
        {
            for (int j=0;j<=1825*100;j++)
            {
                if (j%x>l||j%x<r)b[j]=1;
            }
        }
    }
    for (int i=0;i<=1825*100;i++)if (!b[i]){printf("%d
",i);return 0;}
    puts("impossible");
}

B Breaking Biscuits

(description)

用两条直线截一个凸包,问直线最窄能多窄。

(solution)

可以(O(n))旋转卡壳。

这里我直接写的(O(n^2))暴力,枚举直线卡在哪一点,然后(O(n))找距离最远的另一点。

#include<bits/stdc++.h>
#define maxn 50010
#define eps 1e-8
using namespace std;
typedef double data_type;
struct point{
    data_type x,y;
    int id;
    point(){}
    inline point(data_type _x,data_type _y,int _id){x=_x;y=_y;id=_id;}
    inline point(data_type _x,data_type _y){x=_x;y=_y;}
    inline point     operator+(const point &b)const{return point(x-b.x,y-b.y);}
    inline point     operator-(const point &b)const{return point(x-b.x,y-b.y);}
    inline data_type operator^(const point &b)const{return x*b.y-y*b.x;}//叉乘
    inline data_type operator*(const point &b)const{return x*b.x-y*b.y;}//点乘
    inline bool      operator<(const point &b)const{return x<b.x||x==b.x&&y<b.y;}
}p[maxn];
inline data_type sqr_dist(const point a,point b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
inline double dist(const point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline bool jijiao_cmp(const point &a,const point &b)//顺时针
{
    data_type tmp=(a-p[1])^(b-p[1]);
    if (tmp<-eps)return 0;if (tmp>eps)return 1;
    return sqr_dist(p[1],a)<sqr_dist(p[1],b);
}
inline double calc(point a,point b,point c)
{
    return fabs(((b-a)^(c-a))/dist(a,b));
}
int zhan[maxn],top;
int n;
inline void graham(int n)
{
    top=0;
    for (int i=2;i<=n;i++)if (p[i]<p[1])swap(p[i],p[1]);
    sort(p+2,p+n+1,jijiao_cmp);
    for(int i=1;i<=n;i++)
    {
        while (top>1&&((p[zhan[top]]-p[zhan[top-1]])^(p[i]-p[zhan[top-1]]))<=0)top--;
        zhan[++top]=i;
    }
    int now=n-1;while (now>=1&&((p[now]-p[1])^(p[zhan[top]]-p[1]))==0)zhan[++top]=now--;
}
inline void work()
{
    for (int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
    graham(n);
    n=top;
    double ans=1<<30,cal2;
    for (int i=1;i<=n;i++)
    {
        cal2=0;
        int nex=i+1;if (nex==n+1)nex=1;
        for (int j=1;j<=n;j++)
            if (j!=i&&j!=nex)
            {
                cal2=max(cal2,calc(p[zhan[i]],p[zhan[nex]],p[zhan[j]]));
            }
        ans=min(ans,cal2);
    }
    printf("%.8f
",ans);
}
int main()
{
    while (~scanf("%d",&n)&&n)work();
}
/*
4
0 0
5 0
5 2
0 2
6
81444 14017
80944 13517
81127 12834
81810 12651
82310 13151
82127 13834
8
197 239
208 246
221 241
250 254
220 265
211 258
198 268
163 256
*/

C Cued In

(description)

​ 打桌球,每种颜色的球都有它的分数,如果上一个打的是红球这一个不能打红球。如果上一个不是红球,桌上有红球只能打红球。如果桌上有红球,那么其他颜色的球被打掉可以拿回来,而且下一次还可以统计分数。问能得到的最大分数。

(solution)

​ 直接贪心,各种打球的方案的唯一差异在于拿回来的球的分数不一样。显然拿分数最大的球。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n,sum;
int a[30];
char s[30];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        if (s[1]=='r')a[i]=1;
        else if (s[1]=='y')a[i]=2;
        else if (s[1]=='g')a[i]=3;
        else if (s[1]=='p')a[i]=6;
        else if (s[2]=='r')a[i]=4;
        else if (s[3]=='u')a[i]=5;
        else if (s[3]=='a')a[i]=7;
        sum+=a[i];
    }
    sort(a+1,a+n+1);
    int mx=a[n],tot=0;
    for (int i=1;i<=n;i++)if (a[i]==1)tot++;
    if (mx!=1)
    {
        sum+=tot*mx;
    }else sum=1;
    printf("%d
",sum);
}

D Deranging Hat

(description)

​ 给一个长度不超过(1000)的串(A),已知它被按照字典序排序了,得到新串(B)。现在要用不超过10000次操作从(B)回到(A)。每次操作要交换(B)的两个位置的字符(B_p,B_q),而且要保证(B_p>B_q)。比如样例(A=dude),(B=ddeu),第一次((4,3))交换(B_4,B_3)得到(ddue),第二次交换(B_3,B_2)得到(dude)。只要输出一组方案。

(solution)

​ 直接暴力统计需要修改的乱序的字母,取一个当中最大的,找到这个需要字母修改的乱序位置(显然肯定存在)然后交换。这样每次乱序的字母至少少掉一。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n;
char s[100100],t[100010];
int main()
{
    scanf("%s",s+1);n=strlen(s+1);
    for (int i=1;i<=n;i++)t[i]=s[i];
    sort(t+1,t+n+1);
    while (1)
    {
        int pos=-1,pos2=-1;
        for (int i=1;i<=n;i++)
            if (s[i]!=t[i])
            {
                if (pos==-1)pos=i;
                else if (t[i]>t[pos])pos=i;
            }
        if (pos==-1)return 0;
        for (int i=1;i<=n;i++)
            if (s[i]!=t[i]&&s[i]==t[pos])pos2=i;
        printf("%d %d
",pos,pos2);
        swap(t[pos],t[pos2]);
    }
}

E Education

(description)

​ 每一件物品有质量(W)和价格(V),要求从(m)件物品中买(n)件,这(n)件物品第(i)件的质量不少于(s_i),同时总价格最小。输出方案。

(solution)

​ 把物品和需求都按质量从大到小排,然后枚举需求,把所有质量大等于当前需求的物品扔进堆,取个价值最小的即可。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
#define pa pair<int,int>
using namespace std;
int n,m;
priority_queue<pa,vector<pa>,greater<pa> >q;
struct p{int v,rnk;}a[1000010];  bool operator <(p a,p b){return a.v>b.v;}
struct Q{int v,w,rnk;}b[1000010];bool operator <(Q a,Q b){return a.v>b.v;}
int ans[100100];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)scanf("%d",&a[i].v),a[i].rnk=i;
    sort(a+1,a+n+1);
    for (int i=1;i<=m;i++)scanf("%d",&b[i].v);
    for (int i=1;i<=m;i++)scanf("%d",&b[i].w),b[i].rnk=i;
    sort(b+1,b+m+1);
    int now=1;
    for (int i=1;i<=n;i++)
    {
        while (now<=m&&a[i].v<=b[now].v)
        {
            q.push(mkp(b[now].w,b[now].rnk));
            now++;
        }
        if (q.empty()){puts("impossible");return 0;}
        pa tp=q.top();q.pop();
        ans[a[i].rnk]=tp.second;
    }
    for (int i=1;i<=n;i++)printf("%d ",ans[i]);
}

F Flipping Coins

(description)

(n)个硬币,一开始都是反面向上,一共投(p)次,每次选一个硬币重投,它取得正面和反面的概率都是(frac{1}{2})。问最优策略下投完(p)次之后正面向上的硬币个数的期望的最大值。必须投满(p)

(solution)

​ 硬币和硬币之间没有本质区别,所以只考虑正反面的硬币各有多少个即可。最优策略肯定是只选还是反面的硬币重投。(f[i][j])表示投了i次、有j个正面向上的硬币的概率。

如果(j=n),只能选一个正面的投,(f[i][j])分别有(frac{1}{2})概率转移到(f[i+1][j])(f[i+1][j-1])

如果(j eq n) ,选一个反面的投,(f[i][j])分别有(frac{1}{2})的概率转移到(f[i+1][j+1])(f[i+1][j])

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n,m;
double f[410],g[410],ans;
int main()
{
    scanf("%d%d",&n,&m);
    f[0]=1;
    for (int i=1;i<=m;i++)
    {
        memset(g,0,sizeof(g));
        for (int j=0;j<n;j++)
        {
            g[j]+=f[j]/2;
            g[j+1]+=f[j]/2;
        }
        g[n]+=f[n]/2;
        g[n-1]+=f[n]/2;
        for (int j=0;j<=n;j++)f[j]=g[j];
    }
    for (int i=1;i<=n;i++)ans+=f[i]*i;
    printf("%.8f
",ans);
}

G GentleBots

(description)

​ 两个机器人分别从(x1,y1,z1),(x2,y2,z2)出发,分别要到达(x'1,y'1,z'1),(x'2,y'2,z'2)。每次只能移动一格。要求他们不能在某个时刻处在同一格,也不能在移动过程中交换位置。

(solution)

​ 如果两个机器人下一步要走到同一个点,那么让一个不动,另一个先走即可。

​ 如果两个机器人下一步走完会交换位置,那么让其中一个绕一圈到达,另一个直接走过来,这样就成功交换位置了。

​ 其他坑点不是很坑,可以忽略不计。

#include<bits/stdc++.h>
#define mkp(a,b,c) make_pair(make_pair(a,b),c)
#define paa pair<pair<int,int>,int>
using namespace std;
int tag1,tag2;
int sx1,sy1,sz1,ex1,ey1,ez1;
int sx2,sy2,sz2,ex2,ey2,ez2;
int nx1,ny1,nz1,nx2,ny2,nz2;
int wx1,wy1,wz1,wx2,wy2,wz2;
inline void mv(int x,int y,int z)
{
    sx1+=x;sy1+=y;sz1+=z;
    printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
}
inline void mv2(int x,int y,int z)
{
    sx2+=x;sy2+=y;sz2+=z;
    printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
}
inline void go1(int x,int y,int z)
{
                if (x==1)
                {
                    mv(0,1,0);
                    mv(1,0,0);
                    mv(1,0,0);
                    mv(0,-1,0);
                }else if (x==-1)
                {
                    mv(0,1,0);
                    mv(-1,0,0);
                    mv(-1,0,0);
                    mv(0,-1,0);
                }else if (y==1)
                {
                    mv(1,0,0);
                    mv(0,1,0);
                    mv(0,1,0);
                    mv(-1,0,0);
                }else if (y==-1)
                {
                    mv(1,0,0);
                    mv(0,-1,0);
                    mv(0,-1,0);
                    mv(-1,0,0);
                }else if (z==1)
                {
                    mv(1,0,0);
                    mv(0,0,1);
                    mv(0,0,1);
                    mv(-1,0,0);
                }else if (z==-1)
                {
                    mv(1,0,0);
                    mv(0,0,-1);
                    mv(0,0,-1);
                    mv(-1,0,0);
                }
}
inline void go2(int x,int y,int z)
{
                if (x==1)
                {
                    mv2(0,1,0);
                    mv2(1,0,0);
                    mv2(1,0,0);
                    mv2(0,-1,0);
                }else if (x==-1)
                {
                    mv2(0,1,0);
                    mv2(-1,0,0);
                    mv2(-1,0,0);
                    mv2(0,-1,0);
                }else if (y==1)
                {
                    mv2(1,0,0);
                    mv2(0,1,0);
                    mv2(0,1,0);
                    mv2(-1,0,0);
                }else if (y==-1)
                {
                    mv2(1,0,0);
                    mv2(0,-1,0);
                    mv2(0,-1,0);
                    mv2(-1,0,0);
                }else if (z==1)
                {
                    mv2(1,0,0);
                    mv2(0,0,1);
                    mv2(0,0,1);
                    mv2(-1,0,0);
                }else if (z==-1)
                {
                    mv2(1,0,0);
                    mv2(0,0,-1);
                    mv2(0,0,-1);
                    mv2(-1,0,0);
                }
}
int main()
{
    srand(time(0));
    scanf("%d%d%d%d%d%d",&sx1,&sy1,&sz1,&ex1,&ey1,&ez1);
    scanf("%d%d%d%d%d%d",&sx2,&sy2,&sz2,&ex2,&ey2,&ez2);
    printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
    while (!(sx1==ex1&&sy1==ey1&&sz1==ez1&&sx2==ex2&&sy2==ey2&&sz2==ez2))
    {
        nx1=nx2=ny1=ny2=nz1=nz2=0;
        if (sx1-ex1)nx1=sx1<ex1?1:-1;
        else if (sy1-ey1)ny1=sy1<ey1?1:-1;
        else if (sz1-ez1)nz1=sz1<ez1?1:-1;
        else tag1=1;
        if (sx2-ex2)nx2=sx2<ex2?1:-1;
        else if (sy2-ey2)ny2=sy2<ey2?1:-1;
        else if (sz2-ez2)nz2=sz2<ez2?1:-1;
        else tag2=1;
        wx1=sx1+nx1;wy1=sy1+ny1;wz1=sz1+nz1;
        wx2=sx2+nx2;wy2=sy2+ny2;wz2=sz2+nz2;
        if (wx1==wx2&&wy1==wy2&&wz1==wz2)
        {
            if (tag1)go2(nx2,ny2,nz2);
            else if (tag2)go1(nx1,ny1,nz1);
            else
            {
                sx1=wx1;sy1=wy1;sz1=wz1;
                printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
            }
        }else if (wx1==sx2&&wy1==sy2&&wz1==sz2)
        {
            if (!(wx2==sx1&&wy2==sy1&&wz2==sz1))
            {
                sx1=wx1;sy1=wy1;sz1=wz1;
                sx2=wx2;sy2=wy2;sz2=wz2;
                printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
            }else
            {
                go1(nx1,ny1,nz1);
            }
        }else
        {
                sx1=wx1;sy1=wy1;sz1=wz1;
                sx2=wx2;sy2=wy2;sz2=wz2;
                printf("(%d %d %d) (%d %d %d)
",sx1,sy1,sz1,sx2,sy2,sz2);
        }
    }
}

H Hiker Safety

留坑待补

I Work All Day

(description)

​ 给出(T)(n)个数(h_1...h_n),找一个(h_k)使得(T\%h_k)最小,并且(k)最小。

(solution)

​ 暴力。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n,sum,sv;
int a[30];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",a+i);
    scanf("%d",&sum);
    sv=a[1];
    for (int i=2;i<=n;i++)
    {
        if (sum%a[i]<sum%sv)sv=a[i];
    }
    printf("%d
",sv);
}

J Just A Minim

(description)

​ 一堆(2^k)求和。

(solution)

​ 暴力。

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define mkp make_pair
using namespace std;
int n;
double sum;
int a[30];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        if (x==0)sum+=2;
        if (x==1)sum++;
        if (x==2)sum+=0.5;
        if (x==4)sum+=0.25;
        if (x==8)sum+=0.125;
        if (x==16)sum+=0.0625;
    }
    printf("%.6f
",sum);
}

K Knightsbridge Rises

留坑待补

L Lounge Lizards

(description)

​ 给一个中心点和其他(n)个带权点,如果在某个点i和中心点之间有其他点j,且(v_ileq v_j)则点i被挡住。问有多少个点是不被挡住的。

(solution)

​ 显然只有同一个方向上的点上会存在挡住。所有点相对中心点按照极角排序,然后提出所有方向相同的点,按照到中心点的距离排个序,然后做个最长上升子序列,就是不被挡住的点个数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define eps 1e-8
typedef ll data_type;
struct point{
    data_type x,y,h;
    point(){}
    inline point(data_type _x,data_type _y){x=_x;y=_y;}
    inline point     operator+(const point &b)const{return point(x-b.x,y-b.y);}
    inline point     operator-(const point &b)const{return point(x-b.x,y-b.y);}
    inline data_type operator^(const point &b)const{return x*b.y-y*b.x;}//叉乘
    inline data_type operator*(const point &b)const{return x*b.x-y*b.y;}//点乘
    inline bool      operator<(const point &b)const{return x<b.x||x==b.x&&y<b.y;}
}p[1001000];
int sx,sy,n,ans;
inline data_type sqr_dist(const point a,point b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
inline double dist(const point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline int Quad(point a)
{
    if (a.x>0&&a.y>=0)return 1;
    if (a.x<=0&&a.y>0)return 2;
    if (a.x<0&&a.y<=0)return 3;
    if (a.x>=0&&a.y<0)return 4;
}
inline data_type cmp(const point &a,const point &b,const point &c){return (b-a)^(c-a);}
inline bool jijiao_cmp(const point &a,const point &b)//顺时针
{
    if (Quad(a-p[1])!=Quad(b-p[1]))return Quad(a-p[1])<Quad(b-p[1]);
    data_type mmp=cmp(p[1],a,b);
    if (mmp==0)return sqr_dist(p[1],a)<sqr_dist(p[1],b);;
    return mmp>0;
}
int a[1000100],top,tot;
int f[1000010];
int mn[1000010];
inline int bsearch(int x,int l,int r)
{
    int s=0;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (mn[mid]<x){s=mid;l=mid+1;}
        else r=mid-1;
    }
    return s;
}
inline void solve()
{
    mn[1]=a[1];tot=1;f[1]=1;
    for (int i=2;i<=top;i++)
    {
        int fnd=bsearch(a[i],1,tot);
        if (fnd==tot)mn[++tot]=a[i];
        else if (a[i]<mn[fnd+1])mn[fnd+1]=a[i];
        f[i]=fnd+1;
    }
    ans+=tot;
}
main()
{
    scanf("%lld%lld",&p[1].x,&p[1].y);
    scanf("%lld",&n);n++;
    for (int i=2;i<=n;i++)
    {
        scanf("%lld%lld%lld",&p[i].x,&p[i].y,&p[i].h);
    }
    sort(p+2,p+n+1,jijiao_cmp);
    for (int i=2;i<=n;i++)
    {
        //printf(" %lld %lld %lld
",i,p[i].x,p[i].y);
        if (i==2||i!=2&&((p[i]-p[1])^(p[i-1]-p[1]))==0&&((p[i].x>p[1].x)^(p[i-1].x>p[1].x))==0)a[++top]=p[i].h;
        else
        {
            solve();
            top=1;a[top]=p[i].h;
        }
    }
    if (top)solve();
    printf("%lld
",ans);
}
/*

0 0
24
-2 -2 1
-2 -1 1
-2 0 1
-2 1 1
-2 2 1
-1 -2 1
-1 -1 1
-1 0 1
-1 1 1
-1 2 1
0 -2 1
0 -1 1
0 1 1
0 2 1
1 -2 1
1 -1 1
1 0 1
1 1 1
1 2 1
2 -2 1
2 -1 1
2 0 1
2 1 1
2 2 1


*/
原文地址:https://www.cnblogs.com/zhber/p/8406358.html