2018-2019 ACM-ICPC, Asia East Continent Finals

版权声明: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。 d [ i ] [ j ] [ k ] d[i][j][k] 表示当前为第 i i 个回合,攻击了 j j 次,攻击回合的下标和为 k k 的最大伤害值。

#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点,这种点记为 A A ;与1相连的0点,记为 B B ;与0相连的1点,记为 C C ;与0不相连的1点,记为 D D

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':' ');
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/86100188