2017 ACM-ICPC 亚洲区(南宁赛区)英语阅读网络竞赛

来源:互联网 发布:python模块大全下载 编辑:程序博客网 时间:2024/06/10 14:01

题目链接:2017 ACM-ICPC 亚洲区(南宁赛区)网络赛

A. Weather Patterns

题意:有四种天气,给你一个4*4的矩阵,a[i][j]表示从天气i转变为天气j的概率,然后又四个询问(两种),第一种是,给你两个观察序列,问你按照这个观察序列转变的概率是多少,第二种是给你i和j,表示连续若干天都是i天气或j天气的期望为多少
解析:求概率,那不就是一直乘么,求期望,那不就是几何分布的期望么,您就欺负我英语不好吧!!!

#include <bits/stdc++.h>using namespace std;double pc[5][5];int md[2][1000000];int len[2];int x[2];double ans;int main(void){    for(int i=1;i<=4;i++)        for(int j=1;j<=4;j++)            scanf("%lf",&pc[i][j]);    len[0]=0;    for(int i=0;true;i++)    {        scanf("%d",&md[0][i]);        len[0]++;        if(getchar()=='\n')            break;    }    len[1]=0;    for(int i=0;true;i++)    {        scanf("%d",&md[1][i]);        len[1]++;        if(getchar()=='\n')            break;    }    scanf("%d%d",&x[0],&x[1]);    ans=1.0;    for(int i=1;i<len[0];i++)        ans*=pc[md[0][i-1]][md[0][i]];    printf("%.8f\n",ans);    ans=1.0;    for(int i=1;i<len[1];i++)        ans*=pc[md[1][i-1]][md[1][i]];    printf("%.8f\n",ans);    printf("%.8f\n",1.0/(1.0-pc[x[0]][x[0]]));    printf("%.8f\n",1.0/(1.0-pc[x[1]][x[1]]));    return 0;}

B. Train Seats Reservation

题意:有一辆火车,有100个火车站台,站台编号为1~100,每个乘客能预定k张火车票,从t1站台上车,从t2站台下车,问你这两火车最少要多少个座位才能满足说有乘客的要求
解析:直接开个数组记录下每个站台的时候有多少个座位被座了,然后算一下最大值输出就可以了,记住先下后上(重点)

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll vis[105];int main(void){    int n;    while(scanf("%d",&n))    {        if(n==0)        {            puts("*");            break;        }        memset(vis,0,sizeof(vis));        for(int i=0;i<n;i++)        {            int s,t;            ll k;            scanf("%d %d %lld",&s,&t,&k);            for(int j=min(s,100);j<min(100,t);j++)                vis[j] += k;        }        ll ans = 0;        for(int i=1;i<=100;i++)            ans = max(ans,vis[i]);        printf("%lld\n",ans);    }    return 0;}

D. Path Search with Constraints

题意:好像是求什么(1,1)到(I,J)的最短路径的,要求权值最小,根据样例得出的题意大概就是,给你一个矩阵,题面又告诉你了一个转移方程,然后让你输出最小花费,和路径
解析:大概猜出题意了,想着,动态转移方程都告诉我了,直接套不就好了么,输出路径的时候发现,和答案一点都不想,看了半天题目,猜测是有两个状态要多存一个结点吧。试着交了一下,A了,真的是猜了半年的题意:)

#include<bits/stdc++.h>using namespace std;const int INF=0x7ffffff;double dp[40][40];int marix[40][40];char as[1000];pair<int,int> pre[40][40];int main(){    double a,b;    scanf("%lf%lf",&a,&b);    for(int i=0; i<40; i++)    {        for(int j=0; j<40; j++)            dp[i][j]=INF;    }    int c1 = 1,c2 = 1;    getchar();    while(c1<=6&&gets(as))    {        c2 = 1;        int len = strlen(as);        for(int i=0; i<len;)        {            if(as[i]>='0' && as[i]<='9')            {                int tmp = 0;                while(as[i]>='0' && as[i]<='9' && i<len)                {                    tmp = tmp*10+as[i]-'0';                    i++;                }                marix[c1][c2++] = tmp;            }            else                i++;        }        c1++;    }    dp[1][1]=marix[1][1];    pre[1][1]=make_pair(0,0);    for(int i=1; i<c1; i++)    {        for(int j=1; j<c2; j++)        {            if(j>2&&i>1)            {                if(dp[i-1][j-2]+a*(marix[i][j-1]+marix[i][j])<dp[i][j])                {                    dp[i][j]=dp[i-1][j-2]+a*(marix[i][j-1]+marix[i][j]);                    pre[i][j]=make_pair(i-1,j-2);                }            }            if(i>1&&j>1)            {                if(dp[i-1][j-1]+b*marix[i][j]<dp[i][j])                {                    dp[i][j]=dp[i-1][j-1]+b*marix[i][j];                    pre[i][j]=make_pair(i-1,j-1);                }            }            if(j>1&&i>2)            {                if(dp[i-2][j-1]+a*(marix[i-1][j]+marix[i][j])<dp[i][j])                {                    dp[i][j]=dp[i-2][j-1]+a*(marix[i-1][j]+marix[i][j]);                    pre[i][j]=make_pair(i-2,j-1);                }            }        }    }    vector<pair<int,int> >ans;    printf("%.6f\n",dp[c1-1][c2-1]);    int x = c1-1,y = c2-1;    ans.push_back(make_pair(x,y));    while(x!=1 || y!=1)    {        int tx = pre[x][y].first;        int ty = pre[x][y].second;        if(x-tx==2)            ans.push_back(make_pair(x-1,y));        else if(y-ty==2)            ans.push_back(make_pair(x,y-1));        x = tx,y = ty;        ans.push_back(make_pair(tx,ty));    }//    for(int i=1;i<c1;i++)//    {//        for(int j=1;j<c2;j++)//            printf("%.1f ",dp[i][j]==INF?0:dp[i][j]);//        puts("");//    }//    for(int i=1;i<c1;i++)//    {//        for(int j=1;j<c2;j++)//            printf("(%d,%d) ",pre[i][j].first,pre[i][j].second);//        puts("");//    }    for(int i=ans.size()-1;i>=0;i--)        printf("(%d,%d)\n",ans[i].second,ans[i].first);    return 0;}

F. Overlapping Rectangles

题意:矩形面积并
解析:线段树,直接套模板

#include <bits/stdc++.h>using namespace std;const int maxn = 1e4;typedef long long ll;int n;struct node{    ll l, r, h;    int d;    node() {}    node(int l, int r, int h, int d): l(l), r(r), h(h), d(d) {}    bool operator< (const node& rhs) const    {        return h < rhs.h;    }} a[maxn];ll cnt[maxn << 2];ll sum[maxn << 2],all[maxn];void push_up(int l, int r, int rt){    if(cnt[rt]) sum[rt] = all[r + 1] - all[l];    else if(l == r) sum[rt] = 0;    else sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];}void update(int L, int R, int v, int l, int r, int rt){    if(L <= l && r <= R)    {        cnt[rt] += v;        push_up(l, r, rt);        return;    }    int m = (l + r)>>1;    if(L <= m) update(L, R, v, l, m, rt << 1);    if(R > m) update(L, R, v, m + 1, r, rt << 1 | 1);    push_up(l, r, rt);}int main(){    while(scanf("%d", &n))    {        if(n==0)        {            puts("*");            break;        }        for(int i = 1; i <= n; ++i)        {            ll x1, y1, x2, y2;            scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);            a[i] = node(x1, x2, y1, 1);            a[i + n] = node(x1, x2, y2, -1);            all[i] = x1;            all[i + n] = x2;        }        n <<= 1;        sort(a + 1, a + 1 + n);        sort(all + 1, all + 1 + n);        int m = unique(all + 1, all + 1 + n) - all - 1;        memset(cnt, 0, sizeof cnt);        memset(sum, 0, sizeof sum);        ll ans = 0;        for(int i = 1; i < n; ++i)        {            int l = lower_bound(all + 1, all + 1 + m, a[i].l) - all;            int r = lower_bound(all + 1, all + 1 + m, a[i].r) - all;            if(l < r) update(l, r - 1, a[i].d, 1, m, 1);            ans += sum[1] * (a[i + 1].h - a[i].h);        }        printf("%lld\n",ans);    }    return 0;}

G. Finding the Radius for an Inserted Circle

题意:给你三个半径为R的圆(Ca,Cb,Cc),然后根据这三个圆生成C1,即和之前三个圆相切,然后C2也是类似这样生成的,总之看图就好啦,要求的就是Ck的半径,要直接截断小数点后面的数
解析:其实第一个圆很好求,如下图所示
Markdown
对于第2个圆,一直到第k个圆来说,求法是一样的,如下图所示
Markdown

#include <bits/stdc++.h>using namespace std;double ans[15];int main(void){    int l,k;    double r;    scanf("%d",&l);    scanf("%lf",&r);    ans[1] = r*2.0/sqrt(3.0)-r;    double d = (ans[1]+r)/2.0-ans[1];    for(int i=2;i<=10;i++)    {        ans[i] = d*d/2.0/(r+d);        d -= 2*ans[i];    }    l++;    while(l--)    {        scanf("%d",&k);        if(k==-1)            break;        printf("%d %d\n",k,(int)floor(ans[k]));    }    return 0;}

H. A Cache Simulator

题意:模拟一个缓存器
解析:表示好险队友是计科专业的

#include <bits/stdc++.h>using namespace std;int main(void){    int mcache[64];    memset(mcache,0,sizeof(mcache));    int acnt=0,hcnt=0;    while(1)    {        char c[10];        scanf("%s",c);        if(c[0]=='E'&&c[1]=='N')        {            double ans=100.0*hcnt/acnt;            printf("Hit ratio = %.2f%c",ans,'%');            break;        }        int ad=0;        for(int i=0;i<7;i++)        {            int k;            if(c[i]>='A'&&c[i]<='F')                k=c[i]-'A'+10;            if(c[i]>='0'&&c[i]<='9')                k=c[i]-'0';            ad=ad*16+k;        }        int gid=(ad/16)%64;        if(abs(mcache[gid]-ad)<16)        {            printf("Hit\n");            hcnt++;        }        else        {            printf("Miss\n");            mcache[gid]=ad;        }        acnt++;    }    return 0;}

I. GSM Base Station Identification

题意:给你10个坐标,问你这10个点在哪个正六边形里面(题目的图片上)
解析:当初感觉这题很麻烦不是特别想写,比赛结束后,发现可以通过把每个正六边形的中心表示出来,然后枚举所有正六边形的中心,判断两点间的距离是是否小于5

#include <bits/stdc++.h>using namespace std;struct point{    double x,y;    point() {}    point(double _x,double _y):x(_x),y(_y) {}}ans[15],p;double dis(point p1,point p2){    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}int main(void){    for(int i=0;i<10;i++)    {        scanf("%lf %lf",&p.x,&p.y);        for(int j=-9;j<=10;j++)        {            for(int k=-9;k<=10;k++)            {                //自己在草稿纸上画一下,应该就能发现,六边形的中心坐标满足                point tmp;                tmp.x = 5.0*sqrt(3.0)*j+5*sqrt(3.0)/2.0*k;                tmp.y = 15.0/2.0*k;                if(dis(tmp,p)<=5.0)                    ans[i] = point(j,k);            }        }    }    for(int i=0;i<10;i++)    {        if(i)printf(", ");        printf("[%.f,%.f]",ans[i].x,ans[i].y);    }    puts("");    return 0;}

J. Minimum Distance in a Star Graph

题意:给你5组长度为n的字符串s和e,问你e要执行多少次交换操作才能使得s和e相等,交换操作的定义为:第一个位置的数字和其他交换,仅此而已
解析:直接bfs即可,(一开始bfs不敢交,后面试了一下,发现竟然是WA了,在队友的提醒下,发现自己看错了题目,以为可以任意换。。。。

#include <bits/stdc++.h>using namespace std;map<long long ,int>maple;struct node{    char s[15];    long long v;    int step;}a,b;int n;long long geth(char a[]){    long long res = 0;    for(int i=0;i<n;i++)        res = res*10+a[i]-'0';    return res;}int bfs(){    a.v = geth(a.s);    a.step = 0;    queue<node>q;    q.push(a);    maple[a.v] = 1;    while(!q.empty())    {        node now = q.front();        q.pop();        if(strcmp(now.s,b.s)==0)            return now.step;            for(int j=1;j<n;j++)            {                node tmp = now;                swap(tmp.s[0],tmp.s[j]);                tmp.v = geth(tmp.s);                if(maple.find(tmp.v)!=maple.end())                    continue;                maple[tmp.v] = 1;                tmp.step = now.step+1;                q.push(tmp);            }    }    return -1;}int main(void){    int m = 5;    scanf("%d",&n);    for(int kk=0;kk<m;kk++)    {        maple.clear();        scanf("%s %s",a.s,b.s);        printf("%d\n",bfs());    }    return 0;}

L. The Heaviest Non-decreasing Subsequence Problem

题意:让你求一个最重的不严格递增子序列,也就是给你一个长度要你自己算的序列,每一个序列有一个权值,即该元素为负数,权值为0,该元素>=10000,权值为5,否则权值为1,然后让你求一个最大权值和的子序列(不减)
解析:其实把>=10000的元素,重复5次加到原序列中,然后求一次最长不减子序列即可

#include <bits/stdc++.h>using namespace std;const int INF=1<<30;const int maxn=1000007;int a[300000];int b[maxn];int len,n;int v[300000];int dp[maxn];int main(void){    int x;    len=0;    while(scanf("%d",&x)!=-1)    {        if(x>=10000)        {            v[len]=5;            a[len]=x%10000;        }        else if(x<0)        {            v[len]=0;            a[len]=x;        }        else        {            v[len]=1;            a[len]=x;        }        len++;    }    n=0;    for(int i=0;i<len;i++)        for(int j=0;j<v[i];j++)            b[n++]=a[i];    fill(dp,dp+n,INF);    for(int i=0;i<n;i++)    {        *upper_bound(dp,dp+n,b[i])=b[i];    }    printf("%d\n",lower_bound(dp,dp+n,INF)-dp);    return 0;}

M. Frequent Subsets Problem

题意:给以一个全集U={1,2,…,n},然后又m个全集的子集,现在给你一个α,问你存在几个集合,在这m个集合出现的次数大于等于α*m,输入第一行是n和α,接下来m行分别是m个集合
解析:题目看懂后,应该算是比较好做吧,除去输入不说以外,我的想法是,记录1~n个元素,每个元素在这m个集合里出现的次数,然后答案的集合肯定是这些元素(出现次数大于ceil(α*m))组合起来,那么直接把这些数全都放到一个集合里,然后枚举这个集合的子集是否满足条件,如果满足ans++

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e5+100;int s[maxn];int vis[maxn];char a[maxn];int main(void){    int n;    double b;    scanf("%d %lf",&n,&b);    int m = 0;    getchar();    while(gets(a))    {        int len = strlen(a);        for(int i=0;i<len;)        {            if(a[i]>='0'&&a[i]<='9')            {                int tmp = 0;                while(a[i]>='0'&&a[i]<='9'&&i<len)                {                    tmp = tmp*10+a[i]-'0';                    i++;                }                vis[tmp]++;                s[m] |= 1<<(tmp-1);            }            else                i++;        }        m++;    }    int t = (int)ceil(b*m);    int res = 0;    for(int i=1;i<=n;i++)    {        if(vis[i]>=t)            res |= 1<<(i-1);    }    int ans = 0;    int sub = res;    do    {        int flag=0;        for(int i=0;sub!=0&&i<m;i++)            if((sub|s[i])==s[i])                flag++;        if(flag>=t)        {            ans++;//            printf("%o\n",sub);        }        sub = (sub-1)&res;    }while(sub!=res);    printf("%d\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击