版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/86100188
2018-2019 ACM-ICPC, Asia East Continent Finals
最后一场现场赛,本来过4题有得银机会,却因为模版错误最后卡在了F题。。。现在补了一下发现在现场想复杂了,模版没错也要卡死在精度上。
在此附上吉老师的视频题解
Problem F:Interstellar … Fantasy
思路:将S,T,O投影到一个二维平面上计算,还要判断ST是否与圆O相交。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
struct Point{int x,y,z;}O,S,T;
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y,A.z-B.z};}
int operator*(Point A,Point B){return A.x*B.x+A.y*B.y+A.z*B.z;}
int operator==(Point A,Point B){return A.x==B.x&&A.y==B.y&&A.z==B.z;}
int dis2(Point A,Point B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z);}
double dis(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));}
int main()
{
int cas;
cin>>cas;
while(cas--)
{
int R;
scanf("%d%d%d%d",&O.x,&O.y,&O.z,&R);
scanf("%d%d%d",&S.x,&S.y,&S.z);
scanf("%d%d%d",&T.x,&T.y,&T.z);
if(S==T){puts("0");continue;}//S T重合
double OST=acos((dis2(S,O)+dis2(S,T)-dis2(O,T))/(2*dis(O,S)*dis(S,T)));
double h=sin(OST)*dis(S,O); //圆心到ST的距离
if(h>=R||(O-S)*(T-S)<0||(O-T)*(S-T)<0){printf("%.10f\n",dis(S,T));continue;}//ST不与圆相交
double ang=acos((dis2(S,O)+dis2(T,O)-dis2(S,T))/(2*dis(S,O)*dis(T,O)));
double ans=sqrt(dis2(O,S)-R*R)+sqrt(dis2(O,T)-R*R);
ans+=(ang-acos(R/dis(O,S))-acos(R/dis(O,T)))*R;
printf("%.10f\n",ans);
}
return 0;
}
Problem I: Misunderstood … Missing
思路:倒着DP。
表示当前为第
个回合,攻击了
次,攻击回合的下标和为
的最大伤害值。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll a[110],b[110],c[110];
ll d[2][101][5051];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
memset(d,-1,sizeof d);
int pre=0,now=1;
for(int i=n;i>=1;i--)
{
if(i==n)d[now][1][n]=a[i];
else
{
for(int j=1;j<=n-i;j++)
for(int k=n;k<=(i+n)*(n-i+1)/2;k++)
{
if(d[pre][j][k]==-1)continue;
d[now][j+1][k+i]=max(d[now][j+1][k+i],d[pre][j][k]+a[i]);
d[now][j][k]=max(d[now][j][k],d[pre][j][k]+b[i]*(k-j*i));
d[now][j][k]=max(d[now][j][k],d[pre][j][k]+c[i]*j);
}
}
now^=1;
pre^=1;
memset(d[now],-1,sizeof d[now]);
}
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=n;j<=(1+n)*n/2;j++)ans=max(ans,d[pre][i][j]);
cout<<ans<<endl;
}
return 0;
}
Problem L: Eventual … Journey
思路:我们可以将节点分为4种:与1无边相连的0点,这种点记为
;与1相连的0点,记为
;与0相连的1点,记为
;与0不相连的1点,记为
。
A与B之间的距离为1;
A与C之间的距离为2(当存在0点与1点相连的边时);
A与D之间的距离为3(当存在0点与1点相连的边时)。
任意两节点距离最大为3,我们记录一下每个点与互异的点的连边数,最后遍历一边讨论一下。
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
const int MOD=1e9+7;
typedef long long ll;
int cnt[MAX];
int ans[MAX];
int a[MAX];
int main()
{
int n,m,zero=0,one=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)zero++;
else one++;
}
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
if(a[x]!=a[y])
{
cnt[x]++;
cnt[y]++;
}
}
int A=0,B=0;
for(int i=1;i<=n;i++)
{
if(a[i]==0&&cnt[i])A++;
if(a[i]==1&&cnt[i])B++;
}
for(int i=1;i<=n;i++)
{
ans[i]+=cnt[i];
if(a[i]==0)ans[i]+=zero-1;
else ans[i]+=one-1;
if(cnt[i]==0)
{
if(a[i]==0)
{
ans[i]+=2*B;
ans[i]+=3*(one-B);
}
else
{
ans[i]+=2*A;
ans[i]+=3*(zero-A);
}
}
else
{
if(a[i]==0)ans[i]+=2*(one-cnt[i]);
else ans[i]+=2*(zero-cnt[i]);
}
}
for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
}