CROC-MBTU 2012, Final Round (Online version, Div. 2)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 

最近的比赛打得太捉鸡了,哎。

A:线性扫一遍


B:最讨厌这种题了,喵呜,果然也写挂了。

把“::”展开成若干个‘:’,使得串中刚好7个‘:’,然后再把这8个子串分开。


C:先把中间一样的去重掉。若还剩下m个数,表示如果不去掉某个数的话, 需要转换m-1次。

那么考虑某个数i,先记录一下他自己的个数b[i],如果把数字i去掉,显然会减少b[i]次转换

那么再考虑去掉某个数,两边的数刚好一样,则也不需要转换,再扫描一遍,如果两边的数一样c[i]++

int a[N],b[N],c[N];
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>a[i];
    n=unique(a,a+n)-a;
    for(int i=0;i<n;i++) b[a[i]]++;
    for(int i=1;i<n-1;i++) if(a[i-1]==a[i+1]) c[a[i]]++;
    int ans,mmin=inf;
    for(int i=1;i<=k;i++)
    {
        int tmp=n-b[i]-1-c[i];
        if(tmp<mmin) mmin=tmp,ans=i;
    }
    cout<<ans<<endl;
    return 0;
}

D:纠结题意了半天,其实还是对的。

有个特点,就是起点是固定的,终点不是固定的。

枚举B,那么成了找一个A,使得|OA|+|AB|最短。显然直线最短,那么将A排序,二分求出最靠近直线的那一两个点。计算一下就可以了。

也可以三分,对于某个B,A按Y排序,显然先递减再递增。

vector<pair<double,int> >A;
int n,m,a,b;
double B[N],l[N];
int main()
{
    cin>>n>>m>>a>>b;
    for(int i=1; i<=n; i++)
    {
        double y;
        cin>>y;
        A.pb(mp(y,i));
    }
    sort(A.begin(),A.end());
   // for(int i=0;i<n;i++) cout<<A[i].first<<endl;
    for(int i=1; i<=m; i++) cin>>B[i];
    for(int i=1; i<=m; i++) cin>>l[i];
    double mmin=inf;
    int ansa,ansb;
    for(int i=1; i<=m; i++)
    {
        double y0=B[i]*1.0/b*a;
        int low=0,high=n-1,mid,idx=n-1;
        while(low<=high)
        {
            mid=(low+high)/2;
            if(A[mid].first>y0){idx=mid;high=mid-1;}
            else low=mid+1;
        }
        double tmp=l[i]+sqrt(sqr(a)+sqr(A[idx].first)+0.0)+sqrt(sqr(b-a)+sqr(B[i]-A[idx].first));
        if(tmp<mmin)
        {
            mmin=tmp;
            ansa=A[idx].second;
            ansb=i;
        }
        if(idx>0)
        {
            idx--;
            tmp=l[i]+sqrt(sqr(a)+sqr(A[idx].first)+0.0)+sqrt(sqr(b-a)+sqr(B[i]-A[idx].first));
            if(tmp<mmin)
            {
                mmin=tmp;
                ansa=A[idx].second;
                ansb=i;
            }
        }
    }
    cout<<ansa<<" "<<ansb<<endl;
    return 0;
}

E:直接模拟,记录已经拓展过的,能到达的最左最右位置。

其实比赛的时候想多了,复杂度也只是n*m

int n,m;
char str[105][10005];
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>str[i];
    int des=0;   //方向
    int pos=0;   //当前位置
    int row=0;   //当前行
    int l=0;     //当前能向左延伸最远的
    int r=0;     //向右延伸最远的
    LL ans=0;
    int cnt=0;   //记录两边是否为'#'或者边界
    while(row<n-1)
    {
        //往下掉
        if(str[row+1][pos]=='.')
        {
            ans++;
            l=r=pos;
            row++;
            continue;
        }
        bool flag=false;  //有没有遇见‘#’
        //向右
        if(des==0)
        {
            ans+=r-pos;   //先走到能走的最右边
            pos=r;
            while(str[row+1][pos]!='.')
            {
                if(pos+1<m&&str[row][pos+1]=='.') //下一个是空地,直接走
                {
                    r=pos+1;
                    ans++;
                    pos++;
                }
                else if(pos+1<m&&str[row][pos+1]=='+') //下一个是墙
                {
                    str[row][pos+1]='.';   //破坏
                    des^=1;   //反向
                    ans++;
                    break;
                }
                else
                {
                    ans++;
                    flag=true;
                    des^=1;
                    break;
                }
            }
        }
        else
        {
            ans+=pos-l;
            pos=l;
            while(str[row+1][pos]!='.')
            {
                if(pos&&str[row][pos-1]=='.') //下一个是空地,直接走
                {
                    l=pos-1;
                    ans++;
                    pos--;
                }
                else if(pos&&str[row][pos-1]=='+') //下一个是墙
                {
                    str[row][pos-1]='.';   //破坏
                    des^=1;   //反向
                    ans++;
                    break;
                }
                else
                {
                    ans++;
                    flag=true;
                    des^=1;
                    break;
                }
            }
        }
        if(!flag) cnt=0;
        else cnt++;
        if(cnt>1) break;   //两边都是'#'或者边界
    }
    if(row<n-1) puts("Never");
    else printf("%I64d\n",ans);
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值