十四届北师大校赛题解

来源:互联网 发布:apply js 编辑:程序博客网 时间:2024/05/01 02:54

A.Check In

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51635

题意:


找到所有是bnu的账号数量

思路:

所有是bnu的账号加入map中判重就行了

代码:

//kopyh#include <bits/stdc++.h>using namespace std;int n,m,sum,res,flag;map<string,int>mp;string s,tt="bnu16-";int main(){    int i,j,k,cas,T,t,x,y,z;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%d",&n);        sum=0;mp.clear();        for(i=0;i<n;i++)        {            cin>>s;            string st = s.substr(0,6);            if(st==tt&&mp[s]==0)sum++,mp[s]=1;        }        printf("%d\n",sum);    }    return 0;}



B.Squared Permutation

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51636

题意:


1~n张牌,每张牌对应的值是该牌数值对应位置的牌上的值。求区间和

思路:

区间和直接线段树搞一下,因为修改值时指向的位置改变所以本身的数值改变,而且指向这个位置的数值也会改变,所以更新时是四次更新。

代码:

//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define MOD 1000000007#define N 112345using namespace std;int n,m,sum,res,flag;int a[N],b[N];#define root 1 , n , 1#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1struct node{    long long pos,val;    node(long long x=0,long long y=0){pos=x,val=y;}}arr[N<<2];int tot;void pushUp(int rt){    arr[rt].val = arr[rt<<1].val+arr[rt<<1|1].val;}void updata(int l,int r,int rt,int ql,int qr,long long val){    if(l>qr||ql>r)return;    if(l>=ql&&r<=qr)    {        arr[rt].val = val;        return;    }    int m = (l+r)>>1;    if(ql<=m)updata(lson,ql,qr,val);    if(qr>m)updata(rson,ql,qr,val);    pushUp(rt);}void build(int l,int r,int rt){    if(l == r)    {        arr[rt].val = a[a[++tot]];        arr[rt].pos = tot;        return;    }    int m = (l+r)>>1;    build(lson);    build(rson);    pushUp(rt);}long long query(int l,int r,int rt,int ql,int qr){    if(l>qr||ql>r)        return 0;    if(l>=ql&&r<=qr)        return arr[rt].val;    int m = (l+r)>>1;    return query(lson,ql,qr)+query(rson,ql,qr);}int main(){    int i,j,k,cas,T,t,x,y,z;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%d",&n);        for(i=1;i<=n;i++)scanf("%d",&a[i]);        for(i=1;i<=n;i++)b[a[i]]=i;        tot=0;        build(root);        scanf("%d",&m);        while(m--)        {            scanf("%d%d%d",&z,&x,&y);            if(z==1)            {                a[x]^=a[y],a[y]^=a[x],a[x]^=a[y];                b[a[x]]=x;                b[a[y]]=y;                updata(root,x,x,a[a[x]]);                updata(root,y,y,a[a[y]]);                updata(root,b[y],b[y],a[y]);                updata(root,b[x],b[x],a[x]);            }            else                printf("%lld\n",query(root,x,y));        }    }    return 0;}

D.Air Hockey

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51638

题意:

给出两个冰球的大小及方向,求能相撞时间,或者最近距离

思路:

因为冰球速度方向一定,所以距离一定是一元二次图像,可通过三分求极值,如果极值小于0则相撞,就在极值之前的单调区间上二分0的位置就是碰撞时间,否则极值就是最近距离。

代码:

//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define MOD 1000000007#define N 1123456using namespace std;int n,m,sum,res,flag;double x[2],y[2],R[2],vx[2],vy[2];double dis(double t){    double a = x[0]+vx[0]*t;    double b = y[0]+vy[0]*t;    double c = x[1]+vx[1]*t;    double d = y[1]+vy[1]*t;    return sqrt((c-a)*(c-a)+(d-b)*(d-b))-R[0]-R[1];}int main(){    int i,j,k,cas,T,t;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%lf%lf%lf%lf%lf",&x[0],&y[0],&R[0],&vx[0],&vy[0]);        scanf("%lf%lf%lf%lf%lf",&x[1],&y[1],&R[1],&vx[1],&vy[1]);        double l = 0,r = 1e10;        while(r-l > 1e-7)        {            double ml = l+(r-l)/3;            double mr = r-(r-l)/3;            if(dis(ml)<=dis(mr))r = mr;            else l = ml;        }        if(dis(l)>=1e-6) printf("%.10lf\n",dis(l));        else        {            l = 0;            while(r-l > 1e-7)            {                double m = (r+l)/2;                if(dis(m)>0)l = m;                else r = m;            }            printf("%.10lf\n",l);        }    }    return 0;}


E.Simple Database

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51639

题意:


就是给出一个数据库表的创建表、删除表、插入数据,删除数据,修改数据、查询数据的操作。

思路:

大模拟啦,数据结构课都写过广义表好麻烦,想想就好了。

代码:

N/A


F.Training Plan

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51640

题意:


m天要做n道题,每天的难度为当天做的题的最大难度与最小难度之差的平方,n天的难度之和最小可以是多少。

思路:

考虑到难度是差值的平方,所以难度相近的一起做,所以只要找到已排序的所有题如何分割为n份即可。

显然区间dp,dp[i][j]表示前i天做j题的最小难度,O(n^3)暴力就行了。

代码:

//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f3f3f3f3f#define MOD 1000000007#define N 501using namespace std;int n,m,sum,res,flag;long long a[N],dp[N][N];void init(){    for(int i=1;i<=n;i++)dp[0][i]=INF;    dp[0][0] = 0;}int main(){    int i,j,k,cas,T,t,x,y,z;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%d%d",&n,&m);        init();        for(i=1;i<=n;i++)scanf("%lld",&a[i]);        sort(a+1,a+1+n);        for(i=1;i<=m;i++)            for(j=1;j<=n;j++)            {                dp[i][j] = dp[i-1][j];                for(k=1;k<=j;k++)                    dp[i][j] = min(dp[i][j],dp[i-1][k-1]+abs(a[j]-a[k])*abs(a[j]-a[k]));            }        printf("%lld\n",dp[m][n]);    }    return 0;}



G.Certain Maze

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51641

题意:


给出一个迷宫,每个格子都是一个斜线将各自的4边分成两组,求能否从上面进入下面出去。

思路:

数据只有100*100直接考虑4个方向暴力bfs就行了,开三维数组判断每个格子的每个边是否被便利就行了。

代码:

//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define MOD 1000000007#define N 112using namespace std;int n,m,sum,res,flag;struct node{    int x,y,f;};int vis[N][N][4];int dir[4][2]={-1,0,1,0,0,-1,0,1};char s[N][N];bool bfs(){    queue<node>q;    memset(vis,0,sizeof(vis));    node a,b;    for(int i=1;i<=m;i++)    {        a.x=1;a.y=i;a.f=0;        vis[1][i][0] = 1;        q.push(a);    }    while(!q.empty())    {        a=q.front();q.pop();        if(a.x==n&&(a.f==2&&s[a.x][a.y]=='R'||a.f==3&&s[a.x][a.y]=='L'))            return true;        if(a.f==0)        {            if(s[a.x][a.y]=='R')            {                vis[a.x][a.y][3]=1;                b.x=a.x;b.y=a.y+1;b.f=2;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }            else            {                vis[a.x][a.y][2]=1;                b.x=a.x;b.y=a.y-1;b.f=3;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }        }        else if(a.f==1)        {            if(s[a.x][a.y]=='R')            {                vis[a.x][a.y][2]=1;                b.x=a.x;b.y=a.y-1;b.f=3;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }            else            {                vis[a.x][a.y][3]=1;                b.x=a.x;b.y=a.y+1;b.f=2;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }        }        else if(a.f==2)        {            if(s[a.x][a.y]=='R')            {                vis[a.x][a.y][1]=1;                b.x=a.x+1;b.y=a.y;b.f=0;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }            else            {                vis[a.x][a.y][0]=1;                b.x=a.x-1;b.y=a.y;b.f=1;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }        }        else if(a.f==3)        {            if(s[a.x][a.y]=='R')            {                vis[a.x][a.y][0]=1;                b.x=a.x-1;b.y=a.y;b.f=1;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }            else            {                vis[a.x][a.y][1]=1;                b.x=a.x+1;b.y=a.y;b.f=0;                if(b.x<=n&&b.x>=1&b.y<=m&&b.y>=1&&!vis[b.x][b.y][b.f])                {                    q.push(b);                    vis[b.x][b.y][b.f]=1;                }            }        }    }    return false;}int main(){    int i,j,k,cas,T,t,x,y,z;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%d%d",&n,&m);        for(i=1;i<=n;i++)scanf("%s",s[i]+1);        printf(bfs()?"Yes\n":"No\n");    }    return 0;}



I.Cactus Exploration

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51643

题意:


给出点数和边数,要构造图,使得图联通且没有边同时属于1个以上的环。得分是最大环长度乘以最小环长度,找到最大得分。

思路:

先考虑特殊情况,当m<n-1时显然不联通,当m>2*(n-1)时显然无法满足没有边同时属于1个以上的环,因为最多就是两个点一个环也就是2*(n-1)条边,所以这两种情况都是输出-1。当m==n-1时是一条链输出0,m==n时是一个环输出n*n。

然后考虑一般情况,首先要让所有边都在环上保证总量最大,然后最大值和最小值都尽可能大,所以就是除了最大值之外都是最小值,这样就是要构造一个一个环长度为y其他环为x的图,使得x*y最大。因为y=m-(m-n+1-1)*x,所以答案就是res=(m-(m-n+1-1)*x)*x,一元二次方程组,直接在对称轴附近找整数点求极值就行了。

代码:

//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define MOD 1000000007#define N 1123456using namespace std;long long n,m,sum,res,flag,T;int main(){    scanf("%lld",&T);    while(T--)    {        scanf("%lld%lld",&n,&m);        if (m < n-1 || m>2*n-2)printf("-1\n");        else if (m == n - 1)printf("0\n");        else if (m == n)printf("%lld\n",n*n);        else        {            res=0;            long long p = m/(2*(m-n));            if (p>1 && p<= m/(m-n))res =p*m-(m-n)*p*p;            p++;            if (p<=m/(m-n))res = max(res,p*m-(m-n)*p*p);            printf("%lld\n",res);        }    }    return 0;}

J.Whalyzh's Problem

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51644

题意:

给定n阶方阵B,构造一个只有0和1的1 \times n的向量A,使得(ABA^T-\sum_{i=0}^{n-1}{A[i] \times B[i][i])/\sum_{i=0}^{n-1}{A[i]}的值最大。

思路:

将b数组看作完全图的边权于是答案就是在这个图中选一个点集使得这个子图的边权之和/点数最大。

抽象到这一步就和POJ上一道求最大密度子图的题基本等价了,然后跑网络流求之,感谢q神代码。

代码:

#include <bits/stdc++.h>#define INF 1e8#define EPS 1e-8#define N 100using namespace std;struct Edge{    int v;    double w;    Edge *x;} *e, *lnk[N * N + 9], E[12 * N * N + 9];int TT, S, T, n, m, b[N + 9][N + 9];int g[N * N + 9], h[N * N + 9];int dcmp(double x){    return (x > +EPS) - (x < -EPS);}void add(int u, int v, double w){    e->v = v, e->w = w, e->x = lnk[u], lnk[u] = e++;    e->v = u, e->w = 0, e->x = lnk[v], lnk[v] = e++;}double sap(int u, double flw){    if (u == T) return flw;    double det, sum = .0;    for (Edge *p = lnk[u]; p; p = p->x)        if (h[u] == h[p->v] + 1 && dcmp(p->w))        {            det = sap(p->v, min(p->w, flw - sum));            p->w -= det;            E[(p - E) ^ 1].w += det;            if (dcmp((sum += det) - flw) == 0) return sum;        }    if (h[S] >= m) return sum;    if (--g[h[u]] == 0) h[S] = m;    ++g[++h[u]];    return sum;}bool check(double x){    m = n + n * (n - 1) / 2;    S = ++m, T = ++m;    e = E;    for (int i = 1; i <= m; ++i) lnk[i] = 0;    for (int i = 1; i <= n; ++i) add(i, T, x);    int cnt = n;    double sum = .0;    for (int i = 1; i < n; ++i)        for (int j = i + 1; j <= n; ++j)        {            ++cnt;            if (b[i][j])            {                sum += b[i][j];                add(S, cnt, b[i][j]);            }            add(cnt, i, INF);            add(cnt, j, INF);        }    g[0] = m;    for (int i = 1; i <= m; ++i) g[i] = h[i] = 0;    while (h[S] < m) sum -= sap(S, INF);    return sum > EPS;}int main(){    scanf("%d", &TT);    while (TT--)    {        scanf("%d", &n);        memset(b, 0, sizeof b);        for (int i = 1; i <= n; ++i)            for (int j = 1; j <= n; ++j)            {                int x;                scanf("%d", &x);                if (i < j) b[i][j] += x;                if (i > j) b[j][i] += x;            }        double l = 0, r = 1000, m;        while (fabs(r - l) > EPS)        {            m = (l + r) / 2;            if (check(m)) l = m;            else r = m;        }        printf("%.5f\n", l);    }    return 0;}



K.ACM Battle

题目:

https://www.bnuoj.com/v3/problem_show.php?pid=51645

题意:

给出一个图找到最小边覆盖,如果大于10就输出GG

思路:

最小边覆盖是很复杂的,但是这个题要求不能大于10,那就可以暴力了,每次找出第一条边,枚举这条边的头或者是尾然后删掉所有这个节点覆盖的边,继续枚举,最多10层dfs所以就是2^10*m的复杂度。

代码:

<pre name="code" class="cpp">//kopyh#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define MOD 1000000007#define N 1123456using namespace std;int n,m,sum,res,flag;struct edge{    int u,v;}a,b;vector<edge>t,e[10];int dfs(int dep){    if(!t.size())return 0;    if(dep==10)return 1;    int res=11;    int x=t[0].u,y=t[0].v;    e[dep] = t;    t.clear();    for(int i=0;i<e[dep].size();i++)        if(e[dep][i].u!=x && e[dep][i].v!=x)            t.push_back(e[dep][i]);    res=min(res,dfs(dep+1));    t.clear();    for(int i=0;i<e[dep].size();i++)        if(e[dep][i].u!=y && e[dep][i].v!=y)            t.push_back(e[dep][i]);    res=min(res,dfs(dep+1));    return res+1;}int main(){    int i,j,k,cas,T,x,y,z;    scanf("%d",&T);    cas=0;    while(T--)    {        scanf("%d%d",&n,&m);        t.resize(m);        for(i=0;i<m;i++)            scanf("%d%d",&t[i].u,&t[i].v);        res = dfs(0);        if(res>10)printf("GG\n");        else printf("%d\n",res);    }    return 0;}






0 0
原创粉丝点击