BNU Training 2016.07.15 总结

来源:互联网 发布:js数组冒泡排序 编辑:程序博客网 时间:2024/06/10 23:54

比赛链接 https://acm.bnu.edu.cn/v3/contest_show.php?cid=8010#info

AC 8/10 ,还好=、=

简单总结一下:

A题

就是一个水题,但为什么WA了这么多次呢…
题意没读懂啊!!!

B,D,E题

一水而过,不用说

F题

题意为x * y的棋盘放k个互不攻击的国王有几种方案,答案%1000000007,T组数据。
数据规模
0 < T <= 50
2 <= x,y <= 15
1 <= k <= x*y
这里写图片描述
一看就是状压dp嘛,不过我写的比较挫,代码也比较丑,时间还慢….
f[i][j][k] 前i行放j个国王,且第i行国王摆放状态为第k个合法状态下的方案数
转移简单粗暴
其实时间上应该是A不了的,但是加了个if就过了==
n * m的棋盘最多只能放 ((n+1)/2)*((m+1)/2) 个国王…超过了直接就是0了呗。。。
应该学学q神的姿势…

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<cmath>using namespace std;const int mod=1e9+7;const int maxn=1700;int p[maxn],num[maxn],cnt;int n,m,king;int maxm;int f[16][15*15+1][maxn];vector<int> v[maxn];int calc(int x){    int ans=0;    while(x)    {        ans++;        x-=x&(-x);    }    return ans;}inline bool ok(int x,int y){    if(p[x]&p[y]) return false;    if((p[x]&(p[y]>>1)) || ((p[x]&(p[y]<<1)))) return false;    return true;}int Maxking(int x,int y){    return ((x+1)/2)*((y+1)/2);}int main(){    int sk;    scanf("%d",&sk);    maxm=1<<15;    cnt=0;    for(int mask=0; mask<maxm; mask++)    {        if((mask&(mask>>1))==0)        {            p[cnt]=mask;            num[cnt++]=calc(mask);        }    }    for(int i=0;i<cnt;i++)        for(int j=0;j<cnt;j++)            if(ok(i,j))                v[i].push_back(j);    while(sk--)    {        scanf("%d%d%d",&n,&m,&king);        if(king>Maxking(n,m))        {            printf("0\n");            continue;        }        maxm=1<<m;        memset(f,0,sizeof(f));        f[0][0][0]=1;        for(int i=1; i<=n; i++)            for(int j=0; j<=king; j++)                for(int k=0; p[k]<maxm; k++)                    for(int o=0,sz=v[k].size();o<sz;o++)                        if(num[k]+num[v[k][o]]<=j)                        {                            f[i][j][k]=(f[i][j][k]+f[i-1][j-num[k]][v[k][o]])%mod;                        }        int ans=0;        for(int i=0; p[i]<maxm; i++)            ans=(ans+f[n][king][i])%mod;        printf("%d\n",ans);    }}

G题

题意是x * y的格子,其中只有一个点是起点,要从这个点出发,每一步只能上下左右的走到相邻格子, 格子可以重复经过,要求所有格子都到达过,且最后回到起点,求所需的最少步数。
找规律题
一行(列)时是特例,如果为1 * y的话,(无论起点在哪)答案为2y-2
当行数或列数有偶数时,发现可以不重复走,答案为x * y
都为奇数时想了半天,最后发现只要重复走一个就行,答案为x * y + 1

I题

此题挺有意思的
三维空间,有一个起点,一个终点,点与点的距离花费就是欧式距离。
但是有一些 worm tube(空间里的线段),可以从这线段上任意一个点进入 worm tube ,然后瞬间从这线段上任意一个点出来,这个过充没有花费。问从起点到终点最小花费多少。
数据规模 0 < T <= 50 , 0 <= N <= 50

首先图论模型比较显然,把起点,终点和worm tube看成图论中的点,做个floyd就求出来了。
关键是…点与点之间的边权(花费)是多少呢?
有两种,一是起点或终点到worm tube的花费就是求点到线段的最小距离啦,这个q神讲过,把线段用参数表示,然后就可以三分了嘛,还有个技巧,为了防止eps太小导致TLE,太大又会因精度不够而WA,用for循环for次数就行了嘛。
第二种是,从一个worm tube到另一个的花费,这个就是求线段到线段的最小距离呀,能不能三分套三分呢,不行!会TLE。这怎么办呢…把点到线段的求法改成用叉积点积求一求就好啦,这样快了很多。

好题!
在WA了八九发之后。。。
不知道为什么把eps改成1e-12后神奇的A了!

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<cmath>using namespace std;const double eps = 1e-12;int sgn(double x){    if(abs(x)<eps) return 0;    if(x>eps) return 1;    return -1;}struct Point{    double x, y, z;    Point(double _x = 0, double _y = 0, double _z = 0):x(_x), y(_y), z(_z) {}    Point operator+(const Point& b)const    {        return Point(x + b.x, y + b.y, z + b.z);    }    Point operator-(const Point& b)const    {        return Point(x - b.x, y - b.y, z - b.z);    }    Point operator*(const double & k)const    {        return Point(x * k, y * k, z * k);    }    Point operator/(const double & k)const    {        return Point(x / k, y / k, z / k);    }    Point operator *(const Point &t)const    {        return Point(y*t.z-z*t.y,-x*t.z+z*t.x,x*t.y-y*t.x);    }    double operator ^(const Point &t)const    {        return x*t.x+y*t.y+z*t.z;    }    double dis(const Point &b)const    {        return sqrt((x - b.x) * (x - b.x) + (y - b.y) * (y - b.y) + (z - b.z) * (z - b.z));    }    double dis2(const Point &b)const    {        return (x - b.x) * (x - b.x) + (y - b.y) * (y - b.y) + (z - b.z) * (z - b.z);    }    double len()const    {        return sqrt(x*x+y*y+z*z);    }    double len2()const    {        return x*x+y*y+z*z;    }    void read()    {        scanf("%lf%lf%lf", &x, &y, &z);    }};typedef Point vect;struct Line{    Point s,e;    Line() {}    Line(const Point &_s, const Point &_e):s(_s),e(_e) {}} line[55];double d[55][55];double calc(const Point &p,const vect & a,const Point &b){    return a^(b-p);}double P2L(const Point &p,const Line & a){    Point v=a.e-a.s;    if(sgn((p-a.s)^(v))<=0)return p.dis(a.s);    if(sgn((p-a.e)^(a.s-a.e))<=0) return p.dis(a.e);    return sqrt((v*(p-a.s)).len2()/v.len2());}double L2L(const Line &a,const Line &b){    double l=0,r=1;    Point v=a.e-a.s;    Point s=a.s;    while(abs(l-r)>eps)    {        double x=(l*2+r)/3;        double y=(l+r*2)/3;        Point px=s+v*x;        Point py=s+v*y;        if(sgn(P2L(px,b)-P2L(py,b))<0) r=y;        else l=x;    }    return P2L(s+v*l,b);}int main(){    int n, T;    Point s, t;    scanf("%d", &T);    for(int cas = 1; cas <= T; cas ++)    {        scanf("%d", &n);        s.read();        t.read();        for(int i = 0; i < n; i ++)        {            line[i].s.read();            line[i].e.read();        }        for(int i=0; i<=n+1; i++)            for(int j=0; j<=n+1; j++)                d[i][j]=(i==j)?0:1e99;        d[n][n+1]=d[n+1][n]=s.dis(t);        for(int i=0; i<n; i++)        {            d[n][i]=P2L(s,line[i]);            d[i][n]=d[n][i];            d[n+1][i]=P2L(t,line[i]);            d[i][n+1]=d[n+1][i];        }        for(int i=0; i<n; i++)            for(int j=i; j<n; j++)                if(i!=j)                    d[i][j]=d[j][i]=L2L(line[i],line[j]);        for(int k=0; k<=n+1; k++)            for(int i=0; i<=n+1; i++)                for(int j=0; j<=n+1; j++)                    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);        printf("%.8f\n",d[n][n+1]);    }}

J题

稍微有点复杂的bfs,细心一点就行。

0 0
原创粉丝点击