<>
427. 学姐逗学弟
时间限制 3000 ms 内存限制 131072
KB
KB
题目描述
学弟们来了之后,学姐每天都非常高兴的和学弟一起玩耍。这一天,学姐想出了这样一个游戏,她画了一棵树,树上共有n个节点,现在学姐把m(m≤n)个石子随机放在节点上,每个节点可以放多个,每一次操作是指把每一个节点上的所有石子都往下移动到他某一个子节点(一个节点有多个石子可以分别移动到不同子节点),如果没有子节点则不移动,无法移动的人输。
学姐说,学弟是绅士应该让学姐先走,其实学姐已经策划好了自己一定会赢,但是这时学弟说,学姐先下那么我来画树和放石子吧,学姐惊呆了。现在她来想知道在新的图上,两人都按最优方案走,自己还能不能赢。
输入格式
输入第一行为一个整数T表示数据组数,接下来T组数据,每组开头为两个整数n,m,表示节点个数和石子个数,1≤m≤n≤100000,接下来一行n−1个整数,表示2到n节点的父亲节点编号,接下来一行m个整数,表示每一个石子的位置。数据保证1为根节点。
输出格式
如果学姐能胜利,输出"MengMengDa!",否则输出"So sad..."。没有引号。
输入样例
1
3 1
1 1
1
输出样例
MengMengDa!
裸的every-sg,连sg具体值都不用求,有问题的地方大概就是,当sg==0(必败)的时候,下一步会选取的是长度最小的某必胜态势,当sg==1的时候,选取长度最大的某必败态势.(不要加入必胜态势)
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define MAXN 100002
int step[MAXN];
int first[MAXN];
int next[MAXN];
int to[MAXN];
int sg[MAXN];
int mex(int i){
if(first[i]==-1)return sg[i]=0;
if(sg[i]!=-1)return sg[i];
int p=first[i];
while(p!=-1){
if(mex(to[p])==0)return sg[i]=1;
p=next[p];
}
return sg[i]=0;
}
int edgeindex;
void addedge(int from,int _to){
next[edgeindex]=first[from];
first[from]=edgeindex;
to[edgeindex]=_to;
edgeindex++;
}
int dfs(int i){
if(first[i]==-1)return step[i]=0;
if(step[i]!=-1)return step[i];
int minstatus=0x3ffffff,maxstatus=0;
int p=first[i];
while(p!=-1){
if(sg[to[p]]==0){
maxstatus=max(maxstatus,dfs(to[p])+1);
}
minstatus=min(minstatus,dfs(to[p])+1);
p=next[p];
}
return step[i]=sg[i]==0?minstatus:maxstatus;
}
int main(){
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
memset(sg,-1,sizeof(sg));
memset(first,-1,sizeof(first));
memset(step,-1,sizeof(step));
int n,m;
edgeindex=0;
cin>>n>>m;
int temp;
for(int i=2;i<=n;i++){
cin>>temp;
addedge(temp,i);
}
for(int i=n;i>=1;i--)mex(i); for(int i=n;i>=1;i--)dfs(i); int maxstep=0;
while(m--){
cin>>temp;
maxstep=max(step[temp],maxstep);
}
if(maxstep&1){
cout<<"MengMengDa!"<<endl;
}
else cout<<"So sad..."<<endl;
}
return 0;
}学姐果然萌萌哒
e:
425. 木头人足球赛
时间限制 1000 ms 内存限制 65536 KB题目描述
木头人星的行动速度是地球上乌龟的1/10(所以可以忽略移动的速度),可是他们也热爱运动,尤其是足球。 他们的足球规则跟人类的一样,足球场尺寸为标准 105 * 68,两队各 11 名球员参赛。 假设 Mays 队的每个队员都是专业的球员,踢球都特别准。而她们的对手 Luke 队截球的规律是,如果行进的球离自己的距离不超过d,就可以截球成功。 现在 Mays 队的十号球员拿到了球,如果只允许一次射门,Mays 队能不能进球呢? 足球场在xy平面内,(0,0)至(105,68)矩形范围内,边缘与x,y轴平行且不能站人。其中Luke队的球门为(0, 30)-(0, 38),Mays 队的球门为(105,30)-(105, 38)输入格式
第一行为组数T ,对这T组数据,每组第一行是Mays队十号球员的坐标x0,y0,接下来 11 行为 Luke 队的 1 - 11 号队员的属性 xi,yi,di, 其中xi,yi表示 i 号球员的坐标,di表示i号球员截球能力值。 保证所有坐标不重复且都在球场范围内,x,y为整数,d为正实数 1.0≤d≤3.0。输出格式
每组数据一行,如果 Mays 队10号队员直接可以射门得分,则输出“Shoot!”;如果10号队员不能成功射门,输出"Poor Mays!".输入样例
1
104 34
1 24 2.928
48 25 2.605
15 41 1.312
39 42 2.454
3 12 2.080
18 39 1.564
10 36 2.530
97 13 1.589
101 57 1.844
84 39 2.561
0 33 1.831输出样例
Shoot!
从大尧神那里学到了新姿势,通过3/2pi-angle把需要的角度(pi/2-3pi/3)连续并且取正了,以及直接计算切线与圆心连线的夹角来计算切线角度,这题要是卡高精就完了.卡在"如果截球角度下限超过最大射球角度没有及时退出"上,另外还一直卡在"射了自家球门"上....完全没有思考
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf 0x7fffffff
const double eps = 1e-6;
const double pi=acos(-1);
double calk(int x1,int y1,int x2,int y2){
double b=atan2((y2-y1),(x2-x1));
if(b>eps)b=3*pi/2.0-b;
else if(b<-eps)b=-pi/2.0-b;
else b=3*pi/2.0;
return b;
}
double caldis(int x1,int y1,int x2,int y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
void caldk(int x0,int y0,int x1,int y1,double d,double& ans1,double &ans2){
double dis=caldis(x0,y0,x1,y1);
double a=asin(d/dis);
// cout<<"a"<<a<<endl;
double b=calk(x0,y0,x1,y1);
// cout<<"b"<<b<<endl;
ans1=max(b+a,b-a);
ans2=min(b-a,b+a);
} int x[12],y[12];
double d[12];
struct foot{
double s, e;
};
foot k[11];
bool cmp(foot f1,foot f2){
if(f1.s+eps<f2.s)return true;
return false;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>x[0]>>y[0];
for(int i=1;i<12;i++){
cin>>x[i]>>y[i]>>d[i];
}
bool fl2=false;
for(int i=1;i<12;i++){
if(caldis(x[0],y[0],x[i],y[i])<d[i]+eps){
cout<<"Poor Mays\n"<<endl;
fl2=true;
}
if(fl2)break;
}
if(fl2)continue;
double maxk=calk(x[0],y[0],0,38);
double mink=calk(x[0],y[0],0,30);
for(int i=1;i<12;i++){
caldk(x[0],y[0],x[i],y[i],d[i],k[i-1].e,k[i-1].s);
}
sort(k,k+11,cmp);
//for(int i=0;i<11;i++)cout<<"k"<<i+1<<" "<<k[i].s<<" "<<k[i].e<<endl;
double s=mink,e=mink;
bool fl=false;
for(int i=0;i<11;i++){
if(k[i].s>maxk+eps)break;
if(s+eps<k[i].s){
s=k[i].s;
if(e+eps<k[i].s){fl=true;break;}
}
e=max(e,k[i].e);
//cout<<"s "<<s<<"e"<<e<<endl;
}
if(!fl&&e+eps<maxk)fl=true;
if(fl)cout<<"Shoot!\n";
else cout<<"Poor Mays!\n";
}
return 0;
}