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

题目链接: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值