[题解]April Cook-Off 2017

来源:互联网 发布:多益网络登录器 编辑:程序博客网 时间:2024/06/05 18:34

写在前面

水题就不写了……

Bear and Shop Trip

题意简述

大厨需要k种食材。
n个商店,每个商店出售的食材种类用二进制位给出,每个商店的位置为(xi,yi)
大厨位于(0,0)
在平面上行走花费的代价是它们的欧氏距离。
大厨想购买所有食材并回到起点,求最小代价。

数据范围

1T10
1n36
1k12
1xi,yi1000

思路

我写了一个spfa。
f(i,j)表示到i商店,已经购买到的食材状态为j的最短距离。
点数是n×2k,边数不太好估计,应该比点数稍多一点?
因为很多点是无效的,spfa不会转移到,所以跑得飞快。

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#include<cmath>using namespace std;typedef long long ll;#define INF 1LL<<60template<typename T>void read(T &x){    char ch=getchar();    int f=1;    for (x=0;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());    if (ch=='-') f=-1,ch=getchar();    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    x*=f;}bool get01(){    char ch=getchar();    for (;ch!='0'&&ch!='1';ch=getchar());    return ch=='1';}int T,n,k,lim;int sta[40],x[40],y[40];double dis[40][5000],ans;bool inq[40][5000];queue<pair<int,int> > q;double get_dis(int a,int b){    return sqrt(1.0*(x[a]-x[b])*(x[a]-x[b])+1.0*(y[a]-y[b])*(y[a]-y[b]));}int main(){    read(T);    while (T--)    {        read(n),read(k);        for (int i=1;i<=n;i++)            read(x[i]),read(y[i]);        for (int i=1;i<=n;i++)        {            sta[i]=0;            for (int j=1,u=1<<k-1;j<=k;j++,u>>=1)                sta[i]+=u*get01();        }        lim=1<<k;        for (int i=1;i<=n;i++)            for (int j=0;j<lim;j++)                dis[i][j]=INF;        dis[0][0]=0;        memset(inq,0,sizeof(inq));        inq[0][0]=1;        q.push(make_pair(0,0));        while (!q.empty())        {            pair<int,int> tmp=q.front();            q.pop();            for (int i=1;i<=n;i++)                if (tmp.first!=i)                if (dis[i][tmp.second|sta[i]]>dis[tmp.first][tmp.second]+get_dis(tmp.first,i))                {                    dis[i][tmp.second|sta[i]]=dis[tmp.first][tmp.second]+get_dis(tmp.first,i);                    if (!inq[i][tmp.second|sta[i]])                    {                        inq[i][tmp.second|sta[i]]=1;                        q.push(make_pair(i,tmp.second|sta[i]));                    }                }            inq[tmp.first][tmp.second]=0;        }        ans=INF;        for (int i=1;i<=n;i++)            ans=min(ans,dis[i][lim-1]+get_dis(0,i));        if (ans==INF) puts("-1");        else printf("%.10lf\n",ans);    }    return 0;} 

Bear and Xor of Sums

题意简述

给出一个n个元素的数列。
求所有子串和的异或和。

数据范围

1n300000

思路

按位考虑。
答案中第k位为1,当且仅当所有的和中,这一位出现1的次数为奇数次。
在模2k+1的意义下考虑这个问题,那么问题转化成了:
(sum(i)sum(j))mod2k+12i的个数。
注意这个式子可能是满足sum(i)mod2k+12ksum(j)mod2k+1的。
也可能是满足sum(i)mod2k+1+2k>sum(j)mod2k+1sum(i)mod2k+1<sum(j)mod2k+1
枚举i统计两种情况。
需要离散化。

代码

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;#define MAXN 300010template<typename T>void read(T &x){    char ch=getchar();    for (x=0;ch<'0'||ch>'9';ch=getchar());    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());}struct BIT{    static const int size=300000;    bool d[300010];    void clear()    {        memset(d,0,sizeof(d));    }    int lowbit(int x)    {        return x&(-x);    }    void modify(int x)    {        for (;x<=size;x+=lowbit(x))            d[x]^=1;    }    bool query(int x)    {        bool ret=0;        for (;x;x-=lowbit(x))            ret^=d[x];        return ret;    }}T;int n,tmp,ans;int a[MAXN],b[MAXN],c[MAXN],ord[MAXN];bool flag;bool cmp(int x,int y){    return b[x]<b[y];}int idx(int x){    b[n+1]=x;    int p=upper_bound(ord,ord+n+1,n+1,cmp)-ord-1;    return p==-1 ? n+1 : ord[p];}int main(){    read(n);    for (int i=1;i<=n;i++)        read(a[i]);    for (int i=1;i<=n;i++)        a[i]+=a[i-1];    for (int i=0;i<=23;i++)    {        for (int j=1;j<=n;j++)            b[j]=a[j]&((1<<i+1)-1);        for (int j=0;j<=n;j++)            ord[j]=j;        sort(ord+1,ord+n+1,cmp);        tmp=1;        c[ord[0]]=tmp;        for (int j=1;j<=n;j++)        {            if (b[ord[j]]!=b[ord[j-1]])                tmp++;            c[ord[j]]=tmp;        }        flag=0;        T.clear();        T.modify(c[0]);        for (int j=1;j<=n;j++)        {            flag^=T.query(c[idx(b[j]-(1<<i))])^T.query(c[idx(b[j]+(1<<i))])^T.query(c[idx(b[j])]);            T.modify(c[j]);        }        ans+=flag<<i;    }    printf("%d",ans);    return 0;} 

Best Triangle

题意简述

给定平面上n个点。
求面积不超过k2的最大三角形面积。

数据范围

1n3000

思路

考场上并不会做……
之后膜了一发题解。
O(n2)条线段按照斜率排序(极角序)排序。
顺次枚举每一条直线。
按照第三个点到这条直线的有向面积维护一个序。
可以证明每次转到下一条直线时,从p1,p2转到q1,q2
序受到影响的之只有p1,p2两个点。
每次在序上二分就可以了,注意要二分两次,有向面积要取绝对值。
复杂度O(n2logn)

代码

#include<cstdio>#include<iostream>#include<algorithm>#include<cmath>using namespace std;#define MAXN 3010typedef long long ll;template<typename T>void read(T &x){    char ch=getchar();    int f=1;    for (x=0;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());    if (ch=='-') f=-1,ch=getchar();    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    x*=f;}struct Point{    ll x,y;    Point() {};    Point(ll _x,ll _y)    {        x=_x,y=_y;    }    Point operator - (const Point &n1)    {        return Point(x-n1.x,y-n1.y);    }    double operator * (const Point &n1)    {        return x*n1.y-y*n1.x;    }}P[MAXN];struct Line{    int a,b;    double angg;    Line() {};    Line(int _a,int _b,double _angg)    {        a=_a,b=_b,angg=_angg;    }    bool operator < (const Line &n1) const    {        return angg<n1.angg;    }}L[9000010];ll TriArea(Point a,Point b,Point c){    return (a-b)*(a-c);}bool cmp(int a,int b){    return TriArea(P[a],P[L[1].a],P[L[1].b])<TriArea(P[b],P[L[1].a],P[L[1].b]);}int n,cnt,l,r,mid;int ord[MAXN],rank[MAXN];ll k,tmp,ans;int main(){    read(n),read(k);    for (int i=1;i<=n;i++)        read(P[i].x),read(P[i].y);    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)        {            if (i==j) continue;            L[++cnt]=Line(i,j,atan2(P[j].y-P[i].y,P[j].x-P[i].x));        }    sort(L+1,L+cnt+1);    for (int i=1;i<=n;i++)        ord[i]=i;    sort(ord+1,ord+n+1,cmp);    for (int i=1;i<=n;i++)        rank[ord[i]]=i;    for (int i=1;i<=cnt;i++)    {        l=1,r=n;        while (l<=r)        {            mid=(l+r)>>1;            tmp=TriArea(P[ord[mid]],P[L[i].a],P[L[i].b]);            if (tmp<=k)            {                if (abs(tmp)<=k)                    ans=max(ans,abs(tmp));                l=mid+1;            }            else                r=mid-1;        }        l=1,r=n;        while (l<=r)        {            mid=(l+r)>>1;            tmp=TriArea(P[ord[mid]],P[L[i].a],P[L[i].b]);            if (tmp>=-k)            {                if (abs(tmp)<=k)                    ans=max(ans,abs(tmp));                r=mid-1;            }            else                l=mid+1;        }        if (i==1)        {            if (rank[L[i].a]<rank[L[i].b])            {                swap(ord[rank[L[i].a]],ord[rank[L[i].b]]);                swap(rank[L[i].a],rank[L[i].b]);            }        }        else        {            swap(ord[rank[L[i].a]],ord[rank[L[i].b]]);            swap(rank[L[i].a],rank[L[i].b]);        }    }    printf("%lld",ans==0 ? -1 : ans);    return 0;} 
0 0
原创粉丝点击