2015 上海区域赛 部分题解

【A】给定一个点的初始位置和方向,如果按照这个方向会碰到给定的圆的话,就发生反射。问另外一个点在这个过程中能否被击中?方法:通过方向向量来判断就可以避免斜率不存在这种恶心的情况了。具体见代码吧。你

//
//Created by just_sort 2016/10/23
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;
const int maxn = 200005;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head

const double eps = 1e-10;
const double PI = acos(-1.0);
struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
};
typedef Point Vector;
double dcmp(double x)
{
    if(fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}
Vector operator-(Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator+(Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
bool operator==(const Point &a,const Point &b)
{
    return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}

struct Line{
    Point p;
    Vector v;
    double ang;
    Line(){}
    Line(Point p,Vector v) : p(p),v(v){ang = atan2(v.y,v.x);}
    Point point(double t)
    {
        return Point(p.x+v.x*t,p.y+v.y*t);
    }
    bool operator<(const Line &L) const{
        return ang < L.ang;
    }
};

struct Circle
{
    Point c;
    double r;
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
    Point point(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
};

int jiaodian(Line L, Circle C,double &t1,double &t2,vector<Point>&sol)
{
    double a = L.v.x,b = L.p.x - C.c.x,c = L.v.y,d = L.p.y-C.c.y;
    double e = a*a + c*c,f = 2.0*(a*b+c*d),g = b*b+d*d-C.r*C.r;
    double delta = f*f - 4.0*e*g;
    if(dcmp(delta) < 0) return 0;
    if(dcmp(delta) == 0)
    {
        t1 = t2 = -f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }
    t1 = (-f-sqrt(delta))/(2.0*e);
    t2 = (-f-sqrt(delta))/(2.0*e);
    sol.push_back(L.point(t1));
    sol.push_back(L.point(t2));
    return 2;
}

double dot(Vector A,Vector B)
{
    return A.x*B.x + A.y*B.y;
}
double cross(Vector A,Vector B)
{
    return A.x*B.y - A.y*B.x;
}
bool ONseg(Point p, Point a1, Point a2)
{
    return dcmp(cross(a1-p,a2-p)) == 0 && dcmp(dot(a1-p,a2-p))<0;
}
double len(Vector A)
{
    return sqrt(dot(A,A));
}
double angle(Vector A,Vector B)
{
    return acos(dot(A,B))/len(A)/len(B);
}
double distoline(Point p,Point A,Point B)
{
    Vector v1 = B-A,v2 = p-A;
    return fabs(cross(v1,v2))/len(v1);
}
Vector Normal(Vector A)
{
    double L = len(A);
    return Vector(A.x/L,A.y/L);
}

int main()
{
    int T, ks = 1;
    scanf("%d", &T);
    while(T--)
    {
        Circle C;
        scanf("%lf%lf%lf",&C.c.x,&C.c.y,&C.r);
        Line L;
        scanf("%lf%lf%lf%lf",&L.p.x,&L.p.y,&L.v.x,&L.v.y);
        Point B;
        scanf("%lf%lf",&B.x,&B.y);
        double t1,t2;
        vector<Point>v;
        bool ok = 0;
        int ans = jiaodian(L,C,t1,t2,v);
        if(ans == 0 || ans == 1)
        {
            if(Normal(L.v) == Normal(B-L.p)){
                printf("Case #%d: Yes\n",ks++);
            }
            else{
                printf("Case #%d: No\n",ks++);
            }
            continue;
        }
        Point jiao;
        double len1 = (L.p.x - v[0].x) * (L.p.x - v[0].x) + (L.p.y - v[0].y) * (L.p.y - v[0].y);
        double len2 = (L.p.x - v[1].x) * (L.p.x - v[1].x) + (L.p.y - v[1].y) * (L.p.y - v[1].y);
        if(len1 - len2 > eps) jiao = v[1];
        else jiao = v[0];
        if(Normal(L.v) == Normal(jiao - B)){
            printf("Case #%d: Yes\n",ks++);
            continue;
        }
        Point c = jiao-L.p+jiao-B;
        Point d = C.c-jiao;
        if(Normal(c) == Normal(d)){
            ok = 1;
        }
        else{
            ok = 0;
        }
        if(ok) printf("Case #%d: Yes\n",ks++);
        else printf("Case #%d: No\n",ks++);
    }
}

【B】题意就是给你一个完全二叉树,现在从根节点1走,每次只能往下走。现在,给你一个N和K,K表示给你这个完全二叉树的前K行,从第1行到第K行有很多路径,希望找到一条路径能表示N,路径上的节点可取正也可取负,要求最后的和为N。规律题。用二叉树的最左边一列k个(即从根节点一直向左走k层)即可,然后根据n的奇偶性判断是否要把最下的叶子节点2^k换成2^k+1.因为最左列的和是sum=2^k-1,设d=sum-n,x=d/2,这时只需要用2^0,2^1,2^2,..,2^(k-2)构造出x即可,然后构造x的这些个数取负就好了。当然如果d是奇数的话,最后一个数取2^k+1,则sum变成sum=2^k,那么d=sum-n就又能保证是偶数了。

LL n, k;

int main()
{
    int T, ks = 1;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%lld",&n,&k);
        LL d = (1LL<<k) - n;
        printf("Case #%d:\n",ks++);
        for(int i = 1; i <k; i++)
        {
            if(d & (1LL<<i)) printf("%lld -\n",1LL<<(i-1));
            else printf("%lld +\n",1LL<<(i-1));
        }
        printf("%lld +\n",(1LL<<(k-1)) + (d & 1 ? 0 : 1));
    }
}


【F】水题,模拟即可。

【K】把01串相邻的个数存下来,然后改变的时候计算最大值即可。注意中间只有一个数的情况,比如101那么答案应该是111.

char s[maxn];
LL a[maxn];

int main()
{
    int T,ks = 1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s+1);
        int cnt = 0;
        int cur = s[1] - '0';
        int t = 0;
        memset(a,0,sizeof(a));
        int len = strlen(s+1);
        for(int i = 1; i <= len; i++){
            if(s[i] - '0' == cur){
                t++;
            }
            else{
                a[++cnt] = t;
                cur = s[i] - '0';
                t = 1;
            }
        }
        a[++cnt] = t;
        //for(int i = 1; i <= cnt; i++) cout<<a[i]<<" ";cout<<endl;
        LL ans = 0;
        LL sum = 0;
        for(int i = 1; i <= cnt; i++) sum += 1LL*a[i]*a[i];
        for(int i = 1; i <= cnt; i++){
            if(a[i+1] == 1 && (i+1)<=cnt&&(i+2)<=cnt){
                LL x1 = sum - 1LL*a[i]*a[i]-1LL*a[i+1]*a[i+1]-1LL*a[i+2]*a[i+2];
                x1 = x1 + 1LL*(a[i] + a[i+1] + a[i+2])*(a[i] + a[i+1] + a[i+2]);
                ans = max(ans, x1);
            }
            else if(a[i+1]==1 && (i+1)<=cnt){
                LL x1 = sum - 1LL*a[i]*a[i]-1LL*a[i+1]*a[i+1];
                x1 = x1 + 1LL*(a[i] + a[i+1])*(a[i] + a[i+1]);
                ans = max(ans, x1);
            }
            else if(a[i+1] != 1&&(i+1) <= cnt){
                LL x2 = sum - 1LL*a[i]*a[i] - 1LL*a[i+1]*a[i+1];
                x2 += 1LL*(a[i]-1)*(a[i]-1)+1LL*(a[i+1]+1)*(a[i+1]+1);
                ans = max(ans, x2);
                LL x3 = sum - 1LL*a[i]*a[i] - 1LL*a[i+1]*a[i+1];
                x3 += 1LL*(a[i]+1)*(a[i]+1)+1LL*(a[i+1]-1)*(a[i+1]-1);
                ans = max(ans, x3);
            }
            else{
                ans = max(ans,sum);
            }
        }
        printf("Case #%d: %I64d\n",ks++,ans);
    }
}

【L】给你(x,y) 然后可以走到(x+lcm(x,y),y)或者走到(x,y+lcm(x,y))然后现在给你一个位置,问你起点有多少种。假设x = pt,y =qt 所以(pt,qt),那么下一步就可以走到(pt(1+q),qt)或者走到(pt,(1+p)qt)。那么很显然我们走到了(x,y) 那么上一步就是 (x/(y+1),y)和(x,y/(x+1))。

int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a%b);
}

int ans = 0;

void solve(int x, int y)
{
    ans++;
    if(x < y) swap(x, y);
    if(x % (y + 1) == 0) solve(x / (y + 1), y);
}

int main()
{
    int T, ks = 1;
    scanf("%d", &T);
    while(T--)
    {
        int x, y;
        ans = 0;
        scanf("%d%d",&x,&y);
        int p = gcd(x, y);
        x = x/p, y = y/p;
        solve(x, y);
        printf("Case #%d: %d\n",ks++,ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值