zoukankan      html  css  js  c++  java
  • XIII Open Cup named after E.V. Pankratiev. GP of America

    A. Explosions

    注意到将炸弹按坐标排序后,每个炸弹直接引爆和间接引爆的都是连续的一段区间,因此只需要求出每个炸弹能间接炸到的最左和最右的炸弹即可。

    建立图论模型,炸弹$i$向炸弹$j$连单向边表示$i$爆炸会直接引起$j$的爆炸,那么建完图后求出SCC缩点然后拓扑排序+DP即可求出答案。

    直接建图的边数是$O(n^2)$的,因此用线段树优化建图即可,时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<algorithm>
    #define N 100010
    #define M 1700010
    typedef long long ll;
    struct P{ll x,r;int id;}a[N];
    inline bool cmp(P a,P b){return a.x<b.x;}
    int T,n,i,j,x,ans[N],id[N],l[N<<1],r[N<<1],tot;
    int g[3][N<<1],nxt[3][M],v[3][M],ed,f[N<<1],d[N<<1],vmin[N<<1],vmax[N<<1],q[N<<1],h,t;
    bool vis[N<<1];
    inline void min(int&a,int b){if(a>b)a=b;}
    inline void max(int&a,int b){if(a<b)a=b;}
    inline void read(ll&a){
      char c;bool f=0;a=0;
      while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
      if(c!='-')a=c-'0';else f=1;
      while(((c=getchar())>='0')&&(c<='9'))(a*=10LL)+=c-'0';
      if(f)a=-a;
    }
    inline void add(int x,int y){
      v[0][++ed]=y;nxt[0][ed]=g[0][x];g[0][x]=ed;
      v[1][ed]=x;nxt[1][ed]=g[1][y];g[1][y]=ed;
    }
    inline void ADD(int x,int y){d[y]++;v[2][++ed]=y;nxt[2][ed]=g[2][x];g[2][x]=ed;}
    void build(int a,int b){
      int x=++tot;
      vmin[x]=a,vmax[x]=b;
      if(a==b){id[a]=x;return;}
      int mid=(a+b)>>1;
      add(l[x]=tot+1,x);build(a,mid);
      add(r[x]=tot+1,x);build(mid+1,b);
    }
    void add(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){add(x,p);return;}
      int mid=(a+b)>>1;
      if(c<=mid)add(l[x],a,mid,c,d,p);
      if(d>mid)add(r[x],mid+1,b,c,d,p);
    }
    inline int left(int p,ll x){
      int l=1,r=p-1,mid,t=p;
      while(l<=r)if(a[mid=(l+r)>>1].x>=x)r=(t=mid)-1;else l=mid+1;
      return t;
    }
    inline int right(int p,ll x){
      int l=p+1,r=n,mid,t=p;
      while(l<=r)if(a[mid=(l+r)>>1].x<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    void dfs1(int x){
      vis[x]=1;
      for(int i=g[0][x];i;i=nxt[0][i])if(!vis[v[0][i]])dfs1(v[0][i]);
      q[++t]=x;
    }
    void dfs2(int x,int y){
      vis[x]=0,f[x]=y;
      min(vmin[y],vmin[x]),max(vmax[y],vmax[x]);
      for(int i=g[1][x];i;i=nxt[1][i])if(vis[v[1][i]])dfs2(v[1][i],y);
    }
    void work(){
      for(ed=0,i=1;i<=tot;i++)g[0][i]=g[1][i]=g[2][i]=d[i]=0;tot=0;
      for(i=1;i<=n;i++)read(a[i].x),read(a[i].r),a[i].id=i;
      std::sort(a+1,a+n+1,cmp);
      build(1,n);
      for(i=1;i<=n;i++)add(1,1,n,left(i,a[i].x-a[i].r),right(i,a[i].x+a[i].r),id[i]);
      for(i=1;i<=tot;i++)vis[i]=0;
      for(t=0,i=1;i<=tot;i++)if(!vis[i])dfs1(i);
      for(i=tot;i;i--)if(vis[q[i]])dfs2(q[i],q[i]);
      for(ed=0,i=1;i<=tot;i++)for(j=g[0][i];j;j=nxt[0][j])if(f[i]!=f[v[0][j]])ADD(f[i],f[v[0][j]]);
      for(h=i=1,t=0;i<=tot;i++)if(f[i]==i&&!d[i])q[++t]=i;
      while(h<=t)for(i=g[2][x=q[h++]];i;i=nxt[2][i]){
        min(vmin[v[2][i]],vmin[x]),max(vmax[v[2][i]],vmax[x]);
        if(!(--d[v[2][i]]))q[++t]=v[2][i];
      }
      for(i=1;i<=n;i++)ans[a[i].id]=vmax[f[id[i]]]-vmin[f[id[i]]]+1;
      for(i=1;i<n;i++)printf("%d ",ans[i]);printf("%d
    ",ans[n]);
    }
    int main(){
      while(~scanf("%d",&n)){
        if(!n)return 0;
        work();
      }
    }
    

      

    B. Flooding Fields

    将图分成$h$份,每个点向下一层周围$4$个点以及当前点连边,然后求最大流即可。

    C. Goat Ropes

    设$r_i$表示第$i$个圆的半径,那么有$O(n^2)$个约束条件:$r_i+r_jleq dis(i,j)$,要最大化$sum_{i=1}^n r_i$。这显然是线性规划模型,单纯形求解即可。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    using namespace std;
    const double eps=1e-9;
    typedef vector<double> VD;
    double simplex(vector<VD>A,VD b,VD c){
      int n=A.size(),m=A[0].size()+1,r=n,s=m-1;
      vector<VD> D(n+2,VD(m+1,0));
      vector<int> ix(n+m);
      for(int i=0;i<n+m;i++)ix[i]=i;
      for(int i=0;i<n;i++){
        for(int j=0;j<m-1;j++)D[i][j]=-A[i][j];
        D[i][m-1]=1;D[i][m]=b[i];
        if(D[r][m]>D[i][m])r=i;
      }
      for(int j=0;j<m-1;j++)D[n][j]=c[j];
      D[n+1][m-1]=-1;
      for(double d;;){
        if(r<n){
          int t=ix[s];
          ix[s]=ix[r+m];
          ix[r+m]=t;
          D[r][s]=1.0/D[r][s];
          vector<int> speedUp;
          for(int j=0;j<=m;j++)if(j!=s){
            D[r][j]*=-D[r][s];
            if(D[r][j])speedUp.push_back(j);
          }
          for(int i=0;i<=n+1;i++)if(i!=r){
            for(int j=0;j<speedUp.size();j++)
              D[i][speedUp[j]]+=D[r][speedUp[j]]*D[i][s];
            D[i][s]*=D[r][s];
          }
        }
        r=-1;s=-1;
        for(int j=0;j<m;j++)if(s<0||ix[s]>ix[j])
          if(D[n+1][j]>eps||(D[n+1][j]>-eps&&D[n][j]>eps))s=j;
        if(s<0)break;
        for(int i=0;i<n;i++)if(D[i][s]<-eps)
          if(r<0||(d=D[r][m]/D[r][s]-D[i][m]/D[i][s])<-eps
             ||(d<eps&&ix[r+m]>ix[i+m]))r=i;
        if(r<0)return -1;
      }
      return D[n][m];
    }
    double x[66],y[66];
    inline double dis(int a,int b){
      return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
    }
    int main(){
      int m;
      while(~scanf("%d",&m)){
        if(!m)return 0;
        for(int i=0;i<m;i++)scanf("%lf%lf",&x[i],&y[i]);
        vector<VD>A;
        VD b;
        VD c;
        for(int i=0;i<m;i++)c.push_back(1);
        for(int i=0;i<m;i++)for(int j=0;j<i;j++){
          VD v;
          for(int k=0;k<m;k++)v.push_back(0);
          v[i]=v[j]=1;
          A.push_back(v);
          b.push_back(dis(i,j));
        }
        printf("%.2f
    ",simplex(A,b,c));
      }
    }
    

      

    D. Job Postings

    显然的建图,跑最大费用最大流。

    E. Overlapping Maps

    考虑复数相乘的几何意义:模长相乘,极角相加。

    因此在复数意义下列出一元一次方程然后直接求解即可。

    F. 3D-printing

    三维凸包模板题。

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    using namespace std;
    #define PR 1e-8
    #define N 1000
    struct TPoint{
      double x,y,z;
      TPoint(){}
      TPoint(double _x,double _y,double _z):x(_x),y(_y),z(_z){}
      TPoint operator-(const TPoint p){return TPoint(x-p.x,y-p.y,z-p.z);}
      TPoint operator*(const TPoint p){return TPoint(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);}//叉积
      double operator^(const TPoint p){return x*p.x+y*p.y+z*p.z;}//点积
    };
    struct fac{
      int a,b,c;//凸包一个面上的三个点的编号
      bool ok;//该面是否是最终凸包中的面
    };
    struct T3dhull{
      int n;//初始点数
      TPoint ply[N];//初始点
      int trianglecnt;//凸包上三角形数
      fac tri[N];//凸包三角形
      int vis[N][N];//点i到点j是属于哪个面
      void clear(){n=0;}
      void newnode(){
        scanf("%lf%lf%lf",&ply[n].x,&ply[n].y,&ply[n].z);
        n++;
      }
      double dist(TPoint a){return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);}//两点长度
      double area(TPoint a,TPoint b,TPoint c){return dist((b-a)*(c-a));}//三角形面积*2
      double volume(TPoint a,TPoint b,TPoint c,TPoint d){return (b-a)*(c-a)^(d-a);}//四面体有向体积*6
      double ptoplane(TPoint &p,fac &f){//正:点在面同向
        TPoint m=ply[f.b]-ply[f.a],n=ply[f.c]-ply[f.a],t=p-ply[f.a];
        return (m*n)^t;
      }
      void deal(int p,int a,int b){
        int f=vis[a][b];
        fac add;
        if(tri[f].ok){
          if((ptoplane(ply[p],tri[f]))>PR)dfs(p,f);else{
            add.a=b,add.b=a,add.c=p,add.ok=1;
            vis[p][b]=vis[a][p]=vis[b][a]=trianglecnt;
            tri[trianglecnt++]=add;
          }
        }
      }
      void dfs(int p,int cnt){//维护凸包,如果点p在凸包外更新凸包
        tri[cnt].ok=0;
        deal(p,tri[cnt].b,tri[cnt].a);
        deal(p,tri[cnt].c,tri[cnt].b);
        deal(p,tri[cnt].a,tri[cnt].c);
      }
      bool same(int s,int e){//判断两个面是否为同一面
        TPoint a=ply[tri[s].a],b=ply[tri[s].b],c=ply[tri[s].c];
        return fabs(volume(a,b,c,ply[tri[e].a]))<PR
        &&fabs(volume(a,b,c,ply[tri[e].b]))<PR
        &&fabs(volume(a,b,c,ply[tri[e].c]))<PR;
      }
      void construct(){//构建凸包
        int i,j;
        trianglecnt=0;
        if(n<4)return;
        bool tmp=1;
        for(i=1;i<n;i++){//前两点不共点
          if((dist(ply[0]-ply[i]))>PR){
            swap(ply[1],ply[i]);tmp=0;break;
          }
        }
        if(tmp)return;
        tmp=1;
        for(i=2;i<n;i++){//前三点不共线
          if((dist((ply[0]-ply[1])*(ply[1]-ply[i])))>PR){
            swap(ply[2],ply[i]); tmp=0; break;
          }
        }
        if(tmp)return;
        tmp=1;
        for(i=3;i<n;i++)//前四点不共面
          if(fabs((ply[0]-ply[1])*(ply[1]-ply[2])^(ply[0]-ply[i]))>PR){
            swap(ply[3],ply[i]);tmp=0;break;
          }
        if(tmp)return;
        fac add;
        for(i=0;i<4;i++){//构建初始四面体
          add.a=(i+1)%4,add.b=(i+2)%4,add.c=(i+3)%4,add.ok=1;
          if((ptoplane(ply[i],add))>0) swap(add.b,add.c);
          vis[add.a][add.b]=vis[add.b][add.c]=vis[add.c][add.a]=trianglecnt;
          tri[trianglecnt++]=add;
        }
        for(i=4;i<n;i++){//构建更新凸包
          for(j=0;j<trianglecnt;j++)
            if(tri[j].ok&&(ptoplane(ply[i],tri[j]))>PR){
              dfs(i,j);break;
            }
        }
        int cnt=trianglecnt;
        trianglecnt=0;
        for(i=0;i<cnt;i++)
          if(tri[i].ok)
            tri[trianglecnt++]=tri[i];
      }
      double area(){//表面积
        double ret=0;
        for(int i=0;i<trianglecnt;i++)ret+=area(ply[tri[i].a],ply[tri[i].b],ply[tri[i].c]);
        return ret/2.0;
      }
      double volume(){//体积
        TPoint p(0,0,0);
        double ret=0;
        for(int i=0;i<trianglecnt;i++)ret+=volume(p,ply[tri[i].a],ply[tri[i].b],ply[tri[i].c]);
        return fabs(ret/6);
      }
      int facetri(){return trianglecnt;}//表面三角形数
      int facepolygon(){//表面多边形数
        int ans=0,i,j,k;
        for(i=0;i<trianglecnt;i++){
          for(j=0,k=1;j<i;j++){
            if(same(i,j)){k=0;break;}
          }
          ans+=k;
        }
        return ans;
      }
    }hull;
    int main(){
      int Case;
      while(~scanf("%d",&Case)){
        if(!Case)return 0;
        double ans=0;
        while(Case--){
          int m;
          hull.clear();
          scanf("%d",&m);
          while(m--){
            int k;
            scanf("%d",&k);
            while(k--)hull.newnode();
          }
          hull.construct();
          ans+=hull.volume();
        }
        printf("%.3f
    ",ans);
      }
      return 0;
    }
    

      

    G. Roads

    对于询问$(u,v,w)$,显然只要求出这个图的最大生成树,然后判断$u$到$v$路径上的最小边是否不小于$w$即可。

    注意到修改边权的操作不超过$2000$个,因此离线询问,将边权不会被修改的边拿出来求最大生成树,那么只有上面那$n-1$条边有用,每次修改的时候暴力用这$2000+n-1$条边重新求最小生成树即可。

    对于询问,可以在求最小生成树的时候按秩合并,那么树高就是$O(log n)$的,暴力查询最小值即可。

    时间复杂度$O(mlog m+elog n+2000(n+2000)log n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100010,inf=~0U>>1;
    int n,m,i,Q,q[N][4],vip[N],b[N],cnt,c[N],f[N],d[N],g[N],dep[N],vis[N];
    char op[9];
    struct E{int u,v,w;}e[N];
    inline bool cmp(int x,int y){return e[x].w>e[y].w;}
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    int getf(int x){return f[x]==x?x:getf(f[x]);}
    inline void merge(int x,int y,int z){
      x=getf(x);
      y=getf(y);
      if(x==y)return;
      if(d[x]==d[y])d[x]++;
      if(d[x]<d[y])swap(x,y);
      f[y]=x;
      g[y]=z;
    }
    int dfs(int x){
      if(vis[x])return dep[x];
      vis[x]=1;
      if(f[x]==x)return dep[x]=0;
      return dep[x]=dfs(f[x])+1;
    }
    inline void build(){
      int i;
      sort(c+1,c+cnt+1,cmp);
      for(i=1;i<=n;i++)f[i]=i,d[i]=0,g[i]=inf;
      for(i=1;i<=cnt;i++)merge(e[c[i]].u,e[c[i]].v,e[c[i]].w);
      for(i=1;i<=n;i++)vis[i]=0;
      for(i=1;i<=n;i++)dfs(i);
    }
    inline int ask(int x,int y){
      if(getf(x)!=getf(y))return -1;
      int z=inf;
      while(x!=y){
        if(dep[x]<dep[y])swap(x,y);
        z=min(z,g[x]);
        x=f[x];
      }
      return z;
    }
    int main(){
      while(~scanf("%d%d",&n,&m)){
        if(!n)return 0;
        for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        scanf("%d",&Q);
        for(i=1;i<=Q;i++){
          scanf("%s",op);
          if(op[0]=='B'||op[0]=='R'){
            q[i][0]=0;
            scanf("%d%d",&q[i][1],&q[i][2]);
            vip[q[i][1]]=1;
          }else{
            q[i][0]=1;
            scanf("%d%d%d",&q[i][1],&q[i][2],&q[i][3]);
          }
        }
        for(i=1;i<=m;i++)b[i]=i;
        sort(b+1,b+m+1,cmp);
        for(i=1;i<=n;i++)f[i]=i;
        for(cnt=0,i=1;i<=m;i++)if(vip[i])c[++cnt]=i;
        for(i=1;i<=m;i++)if(!vip[b[i]])if(F(e[b[i]].u)!=F(e[b[i]].v)){
          f[f[e[b[i]].u]]=f[e[b[i]].v];
          c[++cnt]=b[i];
        }
        build();
        for(i=1;i<=Q;i++)if(q[i][0])puts(ask(q[i][1],q[i][2])>=q[i][3]?"1":"0");
        else{
          e[q[i][1]].w=q[i][2];
          build();
        }
        for(i=1;i<=m;i++)vip[i]=0;
        cnt=0;
      }
    }
    

      

    H. Satisfaction Guaranteed

    留坑。

    I. Trading

    对于每个询问,二分答案,然后用Hash值判断是否相等即可,时间复杂度$O(qlog n)$。

    #include<cstdio>
    #include<cstring>
    typedef long long ll;
    const int N=100010,A=1000000007,B=1000000009;
    int n,m,i,x,y;char a[N];ll pa[N],pb[N],f[N],g[N];
    inline ll hasha(int l,int r){return((f[r]-1LL*f[l-1]*pa[r-l+1]%A)%A+A)%A;}
    inline ll hashb(int l,int r){return((g[r]-1LL*g[l-1]*pb[r-l+1]%B)%B+B)%B;}
    inline int ask(int x,int y){
      int l=1,r=n-y+1,mid,t=0;
      while(l<=r){
        mid=(l+r)>>1;
        if(hasha(x,x+mid-1)==hasha(y,y+mid-1)&&hashb(x,x+mid-1)==hashb(y,y+mid-1))l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    int main(){
      for(pa[0]=i=1;i<N;i++)pa[i]=233LL*pa[i-1]%A;
      for(pb[0]=i=1;i<N;i++)pb[i]=233LL*pb[i-1]%B;
      while(~scanf("%s",a+1)){
        if(a[1]=='*')return 0;
        n=strlen(a+1);
        for(i=1;i<=n;i++)f[i]=(233LL*f[i-1]+a[i])%A;
        for(i=1;i<=n;i++)g[i]=(233LL*g[i-1]+a[i])%B;
        scanf("%d",&m);
        while(m--)scanf("%d%d",&x,&y),printf("%d
    ",ask(x+1,y+1));
      }
    }
    

      

    J. Uniform Subtrees

    注意到对于一棵大小为$n$的子树,答案只有$O(n)$个,所以自底向上合并答案,用Hash去重即可。

    时间复杂度$O(n^2log n)$。

    K. Unreal Estate

    将坐标乘上$100$变成整数,然后用线段树求出矩形面积并即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=600000;
    int n,m,i,v[N],tag[N];long long ans;
    struct E{int x,l,r,t;E(){}E(int _x,int _l,int _r,int _t){x=_x,l=_l,r=_r,t=_t;}}e[N];
    inline bool cmp(const E&a,const E&b){return a.x<b.x;}
    void build(int x,int a,int b){
      v[x]=tag[x]=0;
      if(a+1==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid);
      build(x<<1|1,mid,b);
    }
    inline void up(int x,int a,int b){
      if(tag[x]){v[x]=b-a;return;}
      if(a+1==b)v[x]=0;else v[x]=v[x<<1]+v[x<<1|1];
    }
    void change(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){
        tag[x]+=p;
        up(x,a,b);
        return;
      }
      int mid=(a+b)>>1;
      if(c<mid)change(x<<1,a,mid,c,d,p);
      if(d>mid)change(x<<1|1,mid,b,c,d,p);
      up(x,a,b);
    }
    int main(){
      while(~scanf("%d",&n)){
        if(!n)return 0;
        m=0;
        for(i=1;i<=n;i++){
          double x1,y1,x2,y2;
          scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
          x1*=100;y1*=100;x2*=100;y2*=100;
          int X1=round(x1),X2=round(x2),Y1=round(y1),Y2=round(y2);
          Y1+=100000;
          Y2+=100000;
          //[0,200000]
          e[++m]=E(X1,Y1,Y2,1);
          e[++m]=E(X2,Y1,Y2,-1);
        }
        sort(e+1,e+m+1,cmp);
        build(1,0,200000);
        ans=0;
        for(i=1;i<m;i++){
          change(1,0,200000,e[i].l,e[i].r,e[i].t);
          ans+=1LL*v[1]*(e[i+1].x-e[i].x);
        }
        double realans=ans/10000.0;
        printf("%.2f
    ",realans);
      }
    }
    

      

  • 相关阅读:
    ciancd开源
    Deployment Pipeline using Docker, Jenkins, Java
    Jenkins与.NET项目
    设置jenkins代理
    p4 是否能自动merge
    jenkins和docker 使用docker作为slave
    jenkins插件 build timeout和build timestamp
    jenkins 插件开发资料
    jenkins2 pipeline 语法快速参考
    jenkins2 pipeline插件的10个最佳实践
  • 原文地址:https://www.cnblogs.com/clrs97/p/5907263.html
Copyright © 2011-2022 走看看