[ZOJ1021 The Willy Memorial Program]【狗狗40题】【特别特别坑爹】

规模十分之小,但是特别特别坑T_T

一定要看清楚这一段话:

As an example, if we set the target point to level 4 in the left pipe in the figure above, the elapsed time for water to reach that target is assumed to be 5 (not 2), Also note that if the water reaches to the top of a pipe (say in level x), it won’t pour out outside the pipe until empty spaces in connected pipes below level x are filled (if can be filled, i.e. the level of water reaches the connecting links). (Note that there may be some links at level x, to which water is entered). After all such spaces are filled; the water level would not go up further.

然后别的怎么暴力都0MS……

搜狗V5啊,在学校上不了ZOJ,用了搜狗的全网加速就上得了啦……其实就是个代理T_T

const int N=55;
const int INF=0x7FFFFFFF;
int n,m,Target_i,Target_level;
struct Pipe{int x,y,h;}P[N];
struct Link{int p1,p2,y;}L[N];
int level[N];

void gao(){
    int i,j,k,ans=0;
    fill(level,level+n+1,INF);
    level[1]=P[1].y+P[1].h;
    while (1){ //退出条件:1、满了 2、达到target
        for (i=1;i<=n;i++)
          for (j=1;j<=n;j++)
            for (k=1;k<=m;k++)if (L[k].p1==j || L[k].p2==j){
              int x,y;
              if (L[k].p1==j) { x=L[k].p2; y=j; }
                         else { x=L[k].p1; y=j; }
              if (level[x]==INF && level[y]==L[k].y) level[x]=P[x].y+P[x].h;
            }
        int cnt=0,Max=-INF;
        bool check=true;
        for (i=1;i<=n;i++)
          if (level[i]!=INF && level[i]>Max)
              Max=level[i];
        for (i=1;i<=n;i++)
          if (level[i]!=INF && level[i]==Max)
            if (level[i]>P[i].y){
              cnt++;
              level[i]–;
            }
            elseif (level[i]==P[i].y)
              check=false;
        if (!check) cnt=0;
        if (cnt==0){
            puts("No Solution");
            return;
        }
        if (level[Target_i]            cout << ans << endl;
            return;
        }
        ans+=cnt;
    }
}

void add(int k,int x,int y,int l){
    int p1=0,p2=0;
    for (int i=1;i<=n;i++){
      if (y>=P[i].y && y<=P[i].y+P[i].h && P[i].x+1==x) p1=i;
      if (y>=P[i].y && y<=P[i].y+P[i].h && P[i].x==x+l) p2=i;
    }
    L[k].p1=p1;
    L[k].p2=p2;
    L[k].y=y;
}

int main(){
    int Tc,x,y,l;
    cin >> Tc;
    while (Tc–){
        cin >> n;
        for (int i=1;i<=n;i++) cin >> P[i].x >> P[i].y >> P[i].h;
        cin >> m;
        for (int i=1;i<=m;i++){
            cin >> x >> y >> l;
            add(i,x,y,l);
        }
        cin >> Target_i >> Target_level;
        if (Target_level<=P[Target_i].y || Target_level>P[Target_i].y+P[Target_i].h)
            puts("No Solution");
        else
            gao();
    }
}

一些数据:

3

7
10 4 6
7 0 13
12 0 13
3 2 8
0 7 6
1 0 6
5 5 7
13
2 1 5
2 3 1
1 9 2
1 12 4
4 8 1
11 10 1
8 13 4
8 2 4
4 4 3
8 5 2
4 6 1
6 7 1
6 11 1
7 12

3
0 0 1
2 1 1
4 1 2
2
1 1 1
3 2 1
2 2

2
0 0 3
2 3 1
1
1 3 1
1 3

 

Topcoder SRM 500 【Experience】

各路大神齐集,题目难到奇葩。

ACRush滑铁卢500和1000都挂了……

CLJ神犇爆-25……

还有两target是0的,红色爆0一堆……

然后我一进去我的房间,就看到一个熟悉的ID:felix-halim,然后还有个人拼命YM它、YY着到底是谁,突然想起是建这个网站的人:

http://felix-halim.net/uva/hunting.php?id=29277

UVA帝啊T_T(上面是AekdyCoin的号)

不过后来他爆0了。我们房子唯一一个红的也爆0了……

最后本房一共7个人有分,其中有一个是叉人得的分。

其余都是只pass了250pt……

由于我巨慢的手速和思考速度,T_T,我的250只有122.66分了,最后在DIV1里刚刚好200名。

于是rating就涨回去了,终于从Blue Boy变回Yellow Boy了!!!上次由于插件事件爆0那rating跌得叫一个惨啊……

哎,我太蒟蒻了。

Topcoder Member SRM485 DIV 1 1000pt

给定一个凸多边形包围住另一个凸多边形,外面的凸多边形上的每个点都向离自己的最远的在外凸多边形上的点连一条线。然后问,随意取一个在外凸多边形上的点,有多少的概率能取到对应线段与内多边形相交的点。

然后规模是TC的老规矩:50

然后算法就是暴力T_T。但是我暴力好像都写得很长。

第一步:

枚举每条外多边形上的边Point[i]->Point[i+1],然后再枚举Point[j]和Point[k],然后搞Point[j]->Point[k]的中垂线(这个有模板T_T),这个中垂线跑回来和Point[i]->Point[i+1]求交点(没交点就算了)。然后将这些交点按到Point[i]的距离排个序,去重。然后对于这个交点序列,每个点到下一个点形成了线段,然后就找一个到线段离两个端点最远的Point[t],然后这个线段对应的最远点就是Point[t]了。

第二步:

枚举外多边形上的点Point[i],然后枚举内多边形上的点,找到一左一右两个交点L和R(可以加多一层循环判是不是所有点都在它左边或者右边),然后向量Point[i]->L和向量Point[i]->R所夹的位置,就是能够穿过内多边形所对应的位置。然后枚举第一步求的交点序列,如果相邻交点间线段对应的最远点是Point[i],那么就用Point[i]->L和Point[i]->R这两个直线向它求交点,然后分情况讨论一下(我这里好像显然写长了)。

 

T_T,幸好调对第一个样例以后就Y了,不然得Debug个半死。

【CODE】

const double eps=1e-9;

    int sign(double x){
        if (x<-eps) return -1;
        if (x> eps) return1;
        return0;
    }

    int m,n;
    struct TPoint{
        double x,y;
        TPoint operator + (TPoint oth){
            TPoint ret;
            ret.x=x+oth.x;
            ret.y=y+oth.y;
            return ret;
        }
        TPoint operator – (TPoint oth){
            TPoint ret;
            ret.x=x-oth.x;
            ret.y=y-oth.y;
            return ret;
        }
        TPoint operator * (double oth){
            TPoint ret;
            ret.x=x*oth;
            ret.y=y*oth;
            return ret;
        }
        booloperator != (TPoint oth){
            return (sign(x-oth.x)!=0 || sign(y-oth.y)!=0);
        }
        booloperator == (TPoint oth){
            return sign(x-oth.x)==0 && sign(y-oth.y)==0;
        }
        doubleoperator ^ (TPoint oth){
            return x*oth.y-y*oth.x;
        }
    }Site[55],Dep[55];
   
struct TLine{
    double a,b,c;
};

TPoint Rot90(TPoint A){
    TPoint ret;
    ret.x=-A.y;
    ret.y=A.x;
    return ret;
}
   
TLine Get_Line(TPoint A,TPoint B){
    TLine ret;
    ret.a=A.y-B.y;
    ret.b=B.x-A.x;
    ret.c=B.y*A.x-B.x*A.y;
    return ret;
}

TPoint jiao(TLine A,TLine B){
    TPoint ret;
    ret.x=(A.b*B.c-A.c*B.b)/(A.a*B.b-B.a*A.b);
    ret.y=(A.c*B.a-A.a*B.c)/(A.a*B.b-B.a*A.b);
    return ret;
}

double dis(TPoint A,TPoint B){
    return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}

    pair        pair        ret.second=false;
        TLine L2=Get_Line(A,B);
        if (sign(L.a*L2.b-L2.a*L.b)==0) return ret;
        else{
            ret.first=jiao(L,L2);
            if (sign(min(A.x,B.x)-ret.first.x)<=0 && sign(ret.first.x-max(A.x,B.x))<=0
            &&  sign(min(A.y,B.y)-ret.first.y)<=0 && sign(ret.first.y-max(A.y,B.y))<=0){
                if (ret.first==A || ret.first==B) return ret;
                ret.second=true;
                return ret;
            }
        }
        return ret;
    }
   
    vector     vector     vector     int tttt;
   
    bool cmp(TPoint A,TPoint B){
        return dis(A,Site[tttt])    }
   
    void Div_part(){
        int i,j,k,p;
        for (i=0;i            Cut[i].clear();
            Cut[i].push_back(Site[i]);
            Cut[i].push_back(Site[(i+1)%m]);
            for (j=0;j              for (k=j+1;k                  TPoint mid=(Site[j]+Site[k])*0.5;
                  TPoint dir=Rot90(Site[j]-Site[k]);
                  pair                  if (cross.second) Cut[i].push_back(cross.first);
              }
            tttt=i;
            sort(Cut[i].begin(),Cut[i].end(),cmp);
            TV.clear();
            for (j=0;j              if (j==0 || Cut[i][j]!=Cut[i][j-1]) TV.push_back(Cut[i][j]);
            Cut[i]=TV;
            best[i].clear();
            for (p=0;p                int now=0;
                for (j=1;j                  if ( sign( dis(Site[j],TV[p]) – dis(Site[now],TV[p]) )>=0 && sign( dis(Site[j],TV[p+1]) – dis(Site[now],TV[p+1]) )>=0 )
                    now=j;
                best[i].push_back(now);
            }
        }
    }
   
    double ans;
   
    void Rush(){
        int i,j,k,L,R;
        for (i=0;i            for (j=0;j                bool check=true;
                for (k=0;k                  if ( sign( (Dep[j]-Site[i])^(Dep[k]-Site[i]) ) > 0 )  check=false;
                if (check) { L=j; break; }
            }
            for (j=0;j                bool check=true;
                for (k=0;k                  if ( sign( (Dep[j]-Site[i])^(Dep[k]-Site[i]) ) < 0 ) check=false;
                if (check) {R=j; break;}
            }
            for (j=0;j              for (k=0;k                if (best[j][k]==i){
                    pair                    pair                    TPoint Lp=Cut[j][k];
                    TPoint Rp=Cut[j][k+1];
                    if (crossL.second){
                      if (crossR.second)
                          ans+=dis(crossL.first,crossR.first);
                      else{
                          if (sign( (Dep[L]-Site[i])^(Lp-Site[i]) )<=0 && sign( (Dep[R]-Site[i])^(Lp-Site[i]) )>=0 )
                              ans+=dis(Lp,crossL.first);
                          else
                              ans+=dis(Rp,crossL.first);
                      }
                    }
                    else{
                      if (crossR.second){
                          if (sign( (Dep[L]-Site[i])^(Lp-Site[i]) )<=0 && sign( (Dep[R]-Site[i])^(Lp-Site[i]) )>=0 )
                              ans+=dis(Lp,crossR.first);
                          else
                              ans+=dis(Rp,crossR.first);
                      }
                      else{
                          if (sign( (Dep[L]-Site[i])^(Lp-Site[i]) )<=0 && sign( (Dep[R]-Site[i])^(Lp-Site[i]) )>=0
                          &&  sign( (Dep[L]-Site[i])^(Rp-Site[i]) )<=0 && sign( (Dep[R]-Site[i])^(Rp-Site[i]) )>=0)
                              ans+=dis(Lp,Rp);
                      }
                    }
                }
        }
    }
class Deposit {
public:
    double successProbability(vector         m=siteX.size();
        n=depositX.size();
        for (int i=0;i            Site[i].x=siteX[i];
            Site[i].y=siteY[i];
        }
        for (int i=0;i            Dep[i].x=depositX[i];
            Dep[i].y=depositY[i];
        }
        double Sum=0;
        for (int i=0;i        ans=0;
        Div_part();
        Rush();
        return ans/Sum;
    }
};

 

[Topcoder SRM 499]【Solution】

55555,当时在学校没法捉……

250

有n只兔子,其中k(k<=n)只说了话,说话的形式如:和我一样颜色的有A[i]只!

然后问,满足这些话的情况下,n最小能是多少。

就是A[i]一样的贪心组合在一起即可。

550

给定一个数组A[i](i=0~n-1),假设你操作的序列是B[i](i=0~m-1)。

初始时m=1,B[0]=0

然后有3种操作:

1、将某个B[i] +1

2、将某个B[i] -1

3、选一个i然后

for (int j=m;j>i;j–) B[j]=B[j-1];

m++;

然后问最少进行多少操作,B[i]能和A[i]一样。

只要注意到复制以后,i和后面就可以断绝联系,这个区间dp的形式还是很明显的,F[i,j,k]表示区间[i,j]由一个初始时B[i]=k的复制而成至少需要多少次操作,然后枚举复制的位置和复制的长度就可以转移了。O(n^5) TC服务器无压力T_T

还有一种神贪心:

int getMinimum(vector

int ret=lines[0]+lines.size()-1;

for (int i=1;i

 if (lines[i]>lines[i-1]) ret+=lines[i]-lines[i-1];

return ret;

}

暂时只证明了他的充分性,必要性不会证T_T

 

1000

这个我觉得是我见过最简单的1000了啊啊啊T_T。

注意它可以交换相邻两个,那么你想想冒泡排序吧,于是所有的顺序都可以排出来了。所以用数量就可以描述一个点。

Tarjan缩环(注意缩完以后已经是拓扑序的了),然后dp求最长路就行了。每个点权就是k!/(pA! * pB! *pC! *pD!) pA表示’A’的数量……

 

[POJ2451 Uyuw’s Concert]【例题】【半平面交】

给定一个10000*10000的区域,然后给出一些向量,要找一个最大的区域,区域中的点都满足在这个大区域内,并且对每个向量满足在其左手边。

就是裸的半平面交啊……看了ZZY的论文跟着写WA到半死。后来由叉姐精心指导下,围观了神奇的优化版,不再需要上下凸壳合并T_T(这就是ZZY那算法最容易错的地方了)

记录一下算法的流程:

一开始按atan2来极角排序,极角一样的两个半平面选择那个限制得最紧的那个,其它删掉。

然后就按顺序枚举每一个半平面把它们尝试都交起来,并用一个双端队列保存有效的半平面。

可见如果当前半平面如图所示,那么队列就要pop_back了。这个判定的标准是队尾两个半平面的交点不在当前半平面所需要的平面内。

而如果出现如图的半平面,队列就要pop_front了。这个的判定标准是队头两个半平面的交点在当前半平面所的需求之外。

然后还有一堆疑问。

1、G++ WA C++ AC

2、中间枚举删边时还必须先做pop_back再做pop_front,否则会WA。影响这个只有一种可能,就是队中只剩两个半平面,并且它们的交点在当前半平面的需求之外,先pop_front会是前面的被删掉,而先pop_back会是后面的被删掉。那么围观此图,容易发现pop_back才是正确的。

差不多就这样。

【CODE】

 constdouble eps=1e-9;
inline
int sign(double x){
    if (x<-eps) return -1;
    if (x> eps) return  1;
    return0;
}
struct TPoint{
    double x,y;
    inline
    TPoint operator + (TPoint oth){
        TPoint ret;
        ret.x=x+oth.x;
        ret.y=y+oth.y;
        return ret;
    }
    inline
    TPoint operator – (TPoint oth){
        TPoint ret;
        ret.x=x-oth.x;
        ret.y=y-oth.y;
        return ret;
    }
    inline
    doubleoperator ^ (TPoint oth){
        return x*oth.y-y*oth.x;
    }
};
struct TLine{
    TPoint p1,p2;
    double angle;
};

struct abcLine{
    double a,b,c;
};

inline
abcLine Get_Line(TPoint A,TPoint B){
    abcLine ret;
    ret.a=A.y-B.y;
    ret.b=B.x-A.x;
    ret.c=B.y*A.x-B.x*A.y;
    return ret;
}
inline
TPoint jiao(TLine AA,TLine BB){
    TPoint ret;
    abcLine A=Get_Line(AA.p1,AA.p2);
    abcLine B=Get_Line(BB.p1,BB.p2);
    ret.x=(A.b*B.c-A.c*B.b)/(A.a*B.b-B.a*A.b);
    ret.y=(A.c*B.a-A.a*B.c)/(A.a*B.b-B.a*A.b);
    return ret;
}

deque deque inline
bool cmp(TLine A,TLine B){
    int ret=sign(A.angle-B.angle);
    if (ret>0) returntrue;
    if (ret<0) returnfalse;
    if (sign((B.p2-B.p1)^(A.p1-B.p1))>=0) returntrue;
                                     elsereturnfalse;
}
inline
bool check(TLine p0,TLine p1,TLine p2){
    TPoint cross=jiao(p0,p1);
    return sign((p2.p2-p2.p1)^(cross-p2.p1))>0;
}

void solve(){
    int i;
    for (i=0;i    #define S Q.size()
    Q.clear();
    sort(L.begin(),L.end(),cmp);
    for (i=0;i      if (i==0 || sign(L[i].angle-L[i-1].angle)!=0) Q.push_back(L[i]);
    L=Q; Q.clear();
    for (i=0;i        while (S>=2 && !check(Q[S-2],Q[S-1],L[i])) Q.pop_back();
        while (S>=2 && !check(Q[0],Q[1],L[i]))     Q.pop_front();
        Q.push_back(L[i]);
    }
    while (S>=2 && !check(Q[S-2],Q[S-1],Q[0])) Q.pop_back();
    while (S>=2 && !check(Q[0],Q[1],Q[S-1])) Q.pop_front();
    #undef S
    convex.clear();
    if (Q.size()<2) return;
    for (int i=0;i      convex.push_back(jiao(Q[i],Q[(i+1)%Q.size()]));
}
inline
void add(double x1,double y1,double x2,double y2){
    TLine ret;
    ret.p1.x=x1;
    ret.p1.y=y1;
    ret.p2.x=x2;
    ret.p2.y=y2;
    L.push_back(ret);
}

int main(){
    double x1,y1,x2,y2;
    int n;
    scanf("%d",&n);
    L.clear();
    for (int i=0;i        scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
        add(x1,y1,x2,y2);
    }
    add(    0,    0,10000,    0);
    add(10000,    0,10000,10000);
    add(10000,10000,    0,10000);
    add(0,    10000,    0,    0);
    solve();
    double ans=0;
    if (Q.size()>2){
      for (int i=0;i        ans+=convex[i]^convex[(i+1)%convex.size()];
    }
    ans/=2;
    if (ans<0) ans=-ans;
    printf("%.1lfn",ans);
}