2015 ICPC 上海
A - An Easy Physics Problem
Not Easy 啊。
给个射线,和一个圆柱体,射线撞到圆柱体会弹射。判断能否经过给定的点。
折射的时候不能用三角函数旋转,会被卡精度。
$(x,y)$关于直线$ax+by+c=0$的对称点坐标$nx=x-2a\frac{ax+by+c}{a2+b2}$,$ny=y-2b\frac{ax+by+c}{a2+b2}$。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
const db eps = 1e-12;
const db pi = 4.0 * atan(1.0);
int sgn(db x) {
if (x > eps) return 1;
if (x < -eps) return -1;
return 0;
}
struct vec {
db x, y;
vec() {}
vec(db _x, db _y): x(_x), y(_y) {}
vec rotate(db c) {
return vec(x * cos(c) - y * sin(c), x * sin(c) + y * cos(c));
}
};
struct line {
vec p, q;
line() {}
line(vec _x, vec _y): p(_x), q(_y) {}
};
db ox, oy, r, sx, sy, vx, vy, ex, ey;
bool ok;
vec solve() {
db dx = sx - ox;
db dy = sy - oy;
db a = vx * vx + vy * vy;
db b = 2.0 * (vx * dx + vy * dy);
db c = dx * dx + dy * dy - r * r;
db delta = b * b - 4.0 * a * c;
if (delta > eps && b < -eps) {
delta = sqrt(delta);
db t2 = (-b - delta) / (2.0 * a);
if (t2 < -eps) {
ok = 0;
return vec(0, 0);
} else if (t2 > -eps) {
ok = 1;
return vec(t2, t2);
} else {
ok = 1;
return vec(0, 0);
}
}
ok = 0;
return vec(0, 0);
}
bool ison1(db sx, db sy, db vx, db vy, db ex, db ey) {
//if (sgn(sx - ex) == 0 && sgn(sy - ey) == 0) return 1;
db lx = ex - sx;
db ly = ey - sy;
db dl = lx * vy - vx * ly;
if (sgn(dl) == 0) {
if (sgn(vx) != 0) {
db sg = lx / vx;
if (sgn(sg) > 0) return 1;
return 0;
} else if (sgn(vy) != 0) {
db sg = ly / vy;
if (sgn(sg) > 0) return 1;
return 0;
}
}
return 0;
}
bool ison2(db sx, db sy, db vx, db vy, db ex, db ey, db t) {
//if (sgn(sx - ex) == 0 && sgn(sy - ey) == 0) return 1;
db lx = ex - sx;
db ly = ey - sy;
db dl = lx * vy - vx * ly;
if (sgn(dl) == 0) {
if (sgn(vx) != 0) {
db sg = lx / vx;
if (sgn(sg) > 0 && sgn(sg - t) <= 0) return 1;
return 0;
} else if (sgn(vy) != 0) {
db sg = ly / vy;
if (sgn(sg) > 0 && sgn(sg - t) <= 0) return 1;
return 0;
}
}
return 0;
}
db get(db sx, db sy, db xx, db yy, db ox, db oy) {
db l1 = (sx - xx) * (sx - xx) + (sy - yy) * (sy - yy);
l1 = sqrt(l1);
db l2 = r;
db l3 = (sx - ox) * (sx - ox) + (sy - oy) * (sy - oy);
l3 = sqrt(l3);
db COS = l1 * l1 + l2 * l2 - l3 * l3;
COS /= (2.0 * l1 * l2);
db alp = acos(COS);
return alp;
}
vec get2(db sx,db sy,db ox,db oy,db xx,db yy){
db A,B,C;
A=oy-yy;
B=xx-ox;
C=ox*yy-xx*oy;
db rx=sx-2.0*A*(A*sx+B*sy+C)/(A*A+B*B);
db ry=sy-2.0*B*(A*sx+B*sy+C)/(A*A+B*B);
return vec(rx,ry);
}
int main() {
//freopen("in.txt", "r", stdin);
//printf("%.17Lf\n",pi);
//cout<<pi<<endl;
int T, cas = 1;
cin >> T;
while (T--) {
cin >> ox >> oy >> r;
cin >> sx >> sy >> vx >> vy;
cin >> ex >> ey;
vec pt = solve();
bool flg = 0;
//cout<<"#"<<ok<<endl;
if (!ok) {
if (ison1(sx, sy, vx, vy, ex, ey)) {
flg = 1;
}
} else {
if (ison2(sx, sy, vx, vy, ex, ey, pt.x)) {
flg = 1;
}
db xx = sx + vx * pt.x;
db yy = sy + vy * pt.x;
// db angle = get(sx, sy, xx, yy, ox, oy);
// angle = 2.0 * angle - pi;
// vec np = vec(vx, vy);
// db fx1,fy1,fx2,fy2;
// fx1=xx-sx;fy1=yy-sy;
// fx2=ox-sx;fy2=oy-sy;
// if(sgn(fx1*fy2-fx2*fy1)<0)
// np = np.rotate(angle);
// else np = np.rotate(-angle);
// if (ison1(xx, yy, np.x, np.y, ex, ey)) {
// flg = 1;
// }
vec dxd=get2(sx,sy,ox,oy,xx,yy);
//cout<<dxd.x<<" "<<dxd.y<<endl;
if(ison1(xx,yy,dxd.x-xx,dxd.y-yy,ex,ey)){
flg=1;
}
}
if (flg) {
printf("Case #%d: Yes\n", cas++);
} else {
printf("Case #%d: No\n", cas++);
}
}
return 0;
}
B - Binary Tree
似乎是构造题目。J想了一发,得出可以全部用$1$,$2$,...,$2^k$表示出奇数。而且偶数可以-1变成奇数。然后尝试dp。。。
然后发现对于1变号,相当于-2,其他同理。
于是变成贪心。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
//freopen("in.txt","r",stdin);
int T;
ll n,k;
cin>>T;
for(int cas=1;cas<=T;cas++){
scanf("%lld%lld",&n,&k);
printf("Case #%d:\n",cas);
ll s=(1ll<<(k))-1;
//cout<<s<<endl;
ll t=0;
if(n%2==0) n--,t++;
for(ll i=0;i<k-1;i++){
ll tmp = (s-n)/2/(1ll<<i);
//cout<<tmp<<endl;
if(tmp%2==0){
printf("%lld +\n",1ll<<i);
} else {
printf("%lld -\n",1ll<<i);
s-=1ll<<(i+1);
}
}
ll tmp = (s-n)/2;
ll ret = 1ll<<(k-1);
if(t) ret++;
if(tmp%2==0){
printf("%lld +\n",ret);
} else {
printf("%lld -\n",ret);
}
}
return 0;
}
F - Friendship of Frog
#include <bits/stdc++.h>
#define maxn 1050
using namespace std;
typedef long long ll;
int t;
char s[maxn];
int Case=1;
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
int ans=INT_MAX;
int len=strlen(s+1);
for(int i=1;i<=len;i++){
for(int j=i+1;j<=len;j++){
if(s[j]==s[i]) ans=min(ans,j-i);
}
}
if(ans==INT_MAX) ans=-1;
printf("Case #%d: %d\n",Case++,ans);
}
return 0;
}
K - Kingdom of Black and White
最多改变一次,枚举计算判断即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+55;
typedef long long ll;
char s[maxn];
int cnt[maxn];
ll res,tmp,temp;
int main(){
//freopen("in.txt","r",stdin);
int T,cas=1;
cin>>T;
while(T--){
scanf("%s",s+1);
int len=strlen(s+1);
cnt[0]=0;
res=tmp=0;
for(int i=1;i<=len;i++){
if(i!=1&&s[i]==s[i-1])
cnt[i]=cnt[i-1]+1;
else {
tmp+=(ll)cnt[i-1]*cnt[i-1];
cnt[i]=1;
}
}
tmp+=(ll)cnt[len]*cnt[len];
//cout<<tmp<<endl;
for(int i=len-1;i>=1;i--){
if(s[i]==s[i+1])
cnt[i]=cnt[i+1];
}
// for(int i=1;i<=len;i++)
// printf("%d%c",cnt[i]," \n"[i==len]);
res=tmp;
for(int i=1;i<=len;i++){
if(i==1){
if(s[i]==s[i+1]) continue;
temp=tmp-1-(ll)cnt[i+1]*cnt[i+1];
temp+=(ll)((ll)(cnt[i+1]+1)*(cnt[i+1]+1));
if(res<temp) res=temp;
} else if(i==len){
if(s[i-1]==s[i]) continue;
temp=tmp-1-(ll)cnt[i-1]*cnt[i-1];
temp+=(ll)((ll)(cnt[i-1]+1)*(cnt[i-1]+1));
if(res<temp) res=temp;
} else {
if(s[i]==s[i-1]&&s[i]==s[i+1]) continue;
if(s[i]==s[i-1]&&s[i]!=s[i+1]){
temp=tmp-(ll)cnt[i]*cnt[i]-(ll)cnt[i+1]*cnt[i+1];
temp+=(ll)(cnt[i]-1)*(cnt[i]-1)+(ll)(cnt[i+1]+1)*(cnt[i+1]+1);
if(res<temp) res=temp;
} else if(s[i]!=s[i-1]&&s[i]==s[i+1]){
temp=tmp-(ll)cnt[i]*cnt[i]-(ll)cnt[i-1]*cnt[i-1];
temp+=(ll)(cnt[i]-1)*(cnt[i]-1)+(ll)(cnt[i-1]+1)*(cnt[i-1]+1);
if(res<temp) res=temp;
} else {
temp=tmp-1-(ll)cnt[i-1]*cnt[i-1]-(ll)cnt[i+1]*cnt[i+1];
temp+=(ll)(cnt[i-1]+1+cnt[i+1])*(cnt[i-1]+1+cnt[i+1]);
if(res<temp) res=temp;
}
}
}
printf("Case #%d: %lld\n",cas++,res);
}
return 0;
}
L - LCM Walk
不放设$x<y$,那么一定是由$(x,y')$走到$(x,y)$。
并且$(y-y')=lcm(x,y')$,那么两者gcd相等,得到等式$z=\frac{x*y}{x+gcd(x,y)}$。
判断前后gcd相等,不等则break。z表达式得整除(因为1的时候)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ex,ey,lst;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
int main(){
//freopen("in.txt","r",stdin);
int T,cas=1;
cin>>T;
while(T--){
int cnt = 1;
scanf("%lld%lld",&ex,&ey);
lst=gcd(ex,ey);
while(ex>=1&&ey>=1){
if(ex>ey){
ll z=(ex*ey)/(ey+gcd(ex,ey));
//cout<<ey+gcd(ex,ey)<<endl;
ll r=(ex*ey)%(ey+gcd(ex,ey));
// cout<<ex<<" "<<ey<<" "<<z<<endl;
// cout<<r<<endl;
if(r!=0) break;
ex-=z;
if(gcd(ex,ey)!=lst) break;
if(ex>=1) cnt++;
} else if(ex<ey){
ll z=(ex*ey)/(ex+gcd(ex,ey));
ll r=(ex*ey)%(ex+gcd(ex,ey));
// cout<<ex<<" "<<ey<<" "<<z<<endl;
// cout<<r<<endl;
if(r!=0) break;
ey-=z;
if(gcd(ex,ey)!=lst) break;
if(ey>=1) cnt++;
} else {
break;
}
}
printf("Case #%d: %d\n",cas++,cnt);
}
return 0;
}