第四届福建省大学生程序设计竞赛
个人手速思维训练失败。还是面临卡题问题,不会冷静下来想哪里有问题,却一直在代码上修改。
读题确定正确题意是首要。
正确理解样例。
想思路,确定完整思路。
计算时间和空间复杂度,想优化。
编码。
测试特殊数据,一般难想,先别急着交,多测试几组比20分钟罚时要好。
观察返回结果(一般是没过):检查代码,数组,数据范围,细节处理。
检查思路。
本场失败原因:A题题意理解错误,反复提交多次提交测试心存侥幸心理,浪费时间。
B题随便交了一发。
CFEFJ没看。
K题思路有问题,忘了处理只有一个联通块两个人同时点火的而不是一个人点火,没有出样例测试,反复修改写法。
构造题,没确定题意,想到了点可以重合也不敢猜,而是一直在试精度。
构造n个点满足:任意两个点距离不超过1,与原点距离不超过1,n对点的距离等于1,这里一对只算一次,理解错误,也没有枚举题意。n个点构成的凸壳面积不小于0.5不大于0.75。
边长为1的正三角形很容易想到,但是不满足面积关系,所以至少需要四个点,在这个基础上加点最合适了,一个正三角形正好有三对点,而加入的一个点与其中一个点距离为1且满足面积关系即可。其实以一个点为圆心,半径为1,另外两个点之间的圆弧上中点就是要求的点,面积正好0.5,且最大。可以有重点,所以n>4的时候都放在那个位置即可。计算可以用特殊数据构造满足条件即可。
scanf("%d",&n);
if(n<=3) puts("No");
else
{
puts("Yes");
printf("%.6f %.6f\n",0.5,0.0);
printf("%.6f %.6f\n",-0.5,0.0);
printf("%.6f %.6f\n",0.0,-0.866025);
printf("%.6f %.6f\n",0.0,0.133975);
for(int i=5;i<=n;i++) printf("%.6f %.6f\n",0.0,0.133975);
}
Sub-Bipartite Graph
用的种类并查集的思想去试了一发。赛后补题发现:假设存在已有的两个集合,那么对于新加入的点,和哪个集合的边更多就加入另外一个集合。这样贪心能保证留下的边最多,且大于等于m/2,因为每个点都贡献了与自身相连一半以上的边,注意m的范围,用二维数组计数。
int w[N][N];
int a[N],b[N];
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
cls(w,0);
scanf("%d%d",&n,&m);
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
w[u][v]++;
w[v][u]++;
}
int cnt1=0,cnt2=0;
a[cnt1++]=1;
for(int i=2;i<=n;i++)
{
int num1=0,num2=0;
for(int j=0;j<cnt1;j++) num1+=w[i][a[j]];
for(int j=0;j<cnt2;j++) num2+=w[i][b[j]];
if(num1>=num2) b[cnt2++]=i;
else a[cnt1++]=i;
}
printf("%d",cnt1);
for(int i=0;i<cnt1;i++) printf(" %d",a[i]);
puts("");
printf("%d",cnt2);
for(int i=0;i<cnt2;i++) printf(" %d",b[i]);
puts("");
}
return 0;
}
C、D以后再补。
Shooting Game
补题题意又理解错了,不是,看错题了,没看清题目给出的是单位时间的移动向量。
n只蚊子只要路线会经过空间单位圆就能被消灭,但是没有相关板子,于是就想把经过的时间计算出来,那么最少消灭次数就是区间选点的问题了。
注意FZU输入整数只能用整型接受,用double形会TLE。
int cnt;
struct node
{
double x,y;
} p[N];
void cal(int id,double x,double y,double z,double x1,double y1,double z1,double r)
{
// printf("%d: \n",id);
double a=(x1*1.0)*(x1)+(y1*1.0)*(y1)+(z1*1.0)*(z1);
double b=2.0*(x*(x1*1.0)+y*1.0*(y1)+z*1.0*(z1));
double c=1.0*x*x+1.0*y*y+1.0*z*z-r;
if(a==0)
{
if(c<=0)
{
p[cnt].x=0;
p[cnt++].y=INF;
}
return ;
}
double tmp=b*b-4*a*c;
// printf("a=%.2f b=%.2f c=%.2f\n",a,b,c);
if(tmp>=0)
{
tmp=sqrt(tmp);
a*=2.0;
b=-b;
double x=(b-tmp)/a;
double y=(b+tmp)/a;
// printf("x=%.6f y=%.6f\n",x,y);
if(y<0) return ;
p[cnt].x=x;
p[cnt++].y=y;
}
}
int cmp(node a,node b)
{
if(a.y!=b.y) return a.y<b.y;
return a.x<b.x;
}
int main()
{
int t,n;
ll r;
scanf("%d",&t);
int t1=t;
while(t--)
{
cnt=0;
scanf("%d%I64d",&n,&r);
int x,y,z,x1,y1,z1;
r*=r;
for(int i=1; i<=n; i++)
{
scanf("%d%d%d%d%d%d",&x,&y,&z,&x1,&y1,&z1);
cal(i,x,y,z,x1,y1,z1,r);
}
printf("Case %d: %d",t1-t,cnt);
sort(p,p+cnt,cmp);
int ans=0;
if(cnt) ans=1;
double r=p[0].y;
for(int i=0; i<cnt; i++)
{
if(p[i].x<=r) continue;
ans++;
r=p[i].y;
}
printf(" %d\n",ans);
}
return 0;
}
Easy Game
水题,判串长奇偶。
水题,大一的时候没做出来。A每次要减少的最多,那么就要A%x最大,那么X就是A的一半加一的时候。
注意数据范围,输入用I64d.
Moon Game
水题,很多人居然找各种板子判凸多边形导致问题百出。暴力枚举4个点,判面积关系即可,用叉积的性质:三角形有向面积的2倍,注意取abs
struct point
{
ll x,y;
} a[50];
ll multi(point p0,point p1,point p2)
{
return abs((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
int main()
{
int t,n;
scanf("%d",&t);
int t1=t;
while(t--)
{
scanf("%d",&n);
int ans=0;
for(int i=1; i<=n; i++) scanf("%I64d%I64d",&a[i].x,&a[i].y);
printf("Case %d: ",t1-t);
if(n<=3) puts("0");
else
{
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
for(int k=j+1; k<=n; k++)
for(int l=k+1; l<=n; l++)
{
ll a1=multi(a[i],a[j],a[k]);
ll a2=multi(a[i],a[j],a[l]);
ll a3=multi(a[i],a[k],a[l]);
ll a4=multi(a[j],a[k],a[l]);
if(a4==a1+a2+a3||a3==a1+a2+a4||a2==a1+a3+a4||a1==a2+a3+a4) continue;
ans++;
}
pd(ans);
}
}
return 0;
}
2个人各选一个格子点火,求最少需要多少时间烧完所有的汽油格子。
只能各选一次,即联通块个数不超过2,当只有一个连通块的时候是2个人同时点火的,没考虑这里无限WA。。
暴力枚举两个人所选的格子广搜取最大值的最小值即可。
char s[15][15];
int vis[20][20];
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
int n,m;
struct node
{
int x,y,num;
};
void dfs(int x,int y)
{
s[x][y]='*';
for(int i=0; i<4; i++)
{
int xx=x+dir[i][0],yy=y+dir[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&s[xx][yy]=='#') dfs(xx,yy);
}
}
int bfs(int x,int y,int xx,int yy)
{
int ans=0;
queue<node>q;
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
vis[x][y]=vis[xx][yy]=1;
node tmp;
tmp.x=x,tmp.y=y,tmp.num=0;
q.push(tmp);
tmp.x=xx,tmp.y=yy,tmp.num=0;
q.push(tmp);
while(!q.empty())
{
tmp=q.front();
q.pop();
ans=max(ans,tmp.num);
// if(vis[tmp.x][tmp.y]) continue;
for(int i=0; i<4; i++)
{
int nx=tmp.x+dir[i][0],ny=tmp.y+dir[i][1];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&s[nx][ny]=='*'&&!vis[nx][ny])
{
node TC;
TC.x=nx,TC.y=ny,TC.num=tmp.num+1;
vis[nx][ny]=1;
q.push(TC);
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) if(!vis[i][j]&&s[i][j]=='*') ans=INF;
return ans;
}
int main()
{
int t;
scanf("%d",&t);
int t1=t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) scanf("%s",s[i]+1);
printf("Case %d: ",t1-t);
int tot=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m&&tot<3; j++)
if(s[i][j]=='#')
{
tot++;
dfs(i,j);
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// printf("%c",s[i][j]);
// puts("");
// }
if(tot>2) puts("-1");
else
{
int ans=INF;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
for(int i1=1; i1<=n; i1++)
for(int j1=1; j1<=m; j1++)
if(!(i1==i&&j1==j)&&s[i][j]=='*'&&s[i1][j1]=='*')
{
ans=min(ans,bfs(i,j,i1,j1));
// printf("%d %d %d %d %d\n",i,j,i1,j1,bfs(i,j,i1,j1));
}
if(ans==INF) ans=0;
pd(ans);
}
}
return 0;
}
OOXX Game
水题,每次只能翻转一个O,求O个数的奇偶就行。
手速还是不行,容易敲错,读题能力更多的是理解能力不行容易把问题想偏。