【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);
}
}