2017 ACM-ICPC 亚洲区(南宁赛区)网络赛

题目链接


01:https://nanti.jisuanke.com/t/17308
02:https://nanti.jisuanke.com/t/17309
03:https://nanti.jisuanke.com/t/17310
04:https://nanti.jisuanke.com/t/17311
05:https://nanti.jisuanke.com/t/17312
06:https://nanti.jisuanke.com/t/17313
07:https://nanti.jisuanke.com/t/17314
08:https://nanti.jisuanke.com/t/17315
09:https://nanti.jisuanke.com/t/17316
10:https://nanti.jisuanke.com/t/17317
11:https://nanti.jisuanke.com/t/17318
12:https://nanti.jisuanke.com/t/17319
13:https://nanti.jisuanke.com/t/17320
这场还是发挥的不好一共做了7题,配额是2,2,3我尴尬的13题这种水题卡了3个小时,本来可以打的好点的,细节处理还是要注意。

一些题解


01 Weather Patterns

 这道题其实是水题,看懂就好,就是告诉你有4种天气,再给你每个天气下一天转到的天气的概率,再给你一系列观察顺序,问你是这样顺序的概率,再给你两个数,问你一直是这两个数的概率。
 那么其实只要把他给的顺序都乘起来就是所求的第一组的值,而第二组的值就是一直用这个天气到这个天气的值相乘然后每乘一次加一次即可。

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;

int main()
{

    double maps[5][5];
    for(int i=1;i<=4;i++)
       for(int j=1;j<=4;j++)
            scanf("%lf",&maps[i][j]);

        int a,b;
        double ans1;
        scanf("%d",&a);
        ans1=1;
        while(getchar()!='\n')
        {
           scanf("%d",&b);
           ans1*=maps[a][b];
           a=b;
        }
       printf("%.8f\n",ans1);
         scanf("%d",&a);
        ans1=1;
        while(getchar()!='\n')
        {
           scanf("%d",&b);
           ans1*=maps[a][b];
           a=b;
        }
       printf("%.8f\n",ans1);
       scanf("%d",&a);
       double ans=1,now=maps[a][a];
       while(now>2*1e-9)
       {
           ans+=now;
           now*=maps[a][a];
       }
        printf("%.8f\n",ans);
        scanf("%d",&a);
       ans=1,now=maps[a][a];
       while(now>2*1e-9)
       {
           ans+=now;
           now*=maps[a][a];
       }
        printf("%.8f\n",ans);
}

02 Train Seats Reservation

 给你一段数字区间需要几个空位,问你最多从头到尾需要几个空位。
 那么只要离散化处理数字区间,然后开始打上正标记,结束打上负标记,从头到尾跑一边就好。

#include <bits/stdc++.h>

using namespace std;
map<int, int>M;
struct Node
{
    int num;
    int val;
}node[2005];
int n;
int cmpp(Node a, Node b)
{
    return a.val < b.val;
}
int main()
{
    while(scanf("%d", &n) != EOF)
    {
        if(n == 0)
        {
            printf("*\n");
            break;
        }
        M.clear();
        int cntt = 0;
        for(int i = 1;i <= n;i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            if(M[a] == 0)
                M[a] = ++cntt, node[M[a]].val = a, node[M[a]].num = 0;
            if(M[b] == 0)
                M[b]= ++cntt,  node[M[b]].val = b, node[M[b]].num = 0;
            node[M[a]].num += c;
            node[M[b]].num -= c;
        }
        sort(node + 1, node + 1 + cntt, cmpp);
        int ans = 0;
        int dq = 0;
        for(int i = 1;i <= cntt;i++)
        {
            dq += node[i].num;
            if(dq > ans)
                ans = dq;
        }
        printf("%d\n", ans);
    }
    return 0;
}

06 Overlapping Rectangles

 队友搞的,说是扫描线填充裸,原题,表示懵逼。

#include <bits/stdc++.h>
#define Ls i << 1
#define Rs i << 1 | 1
#define lson Ls, l, M
#define rson Rs, M + 1, r
#define root 1, 0, k - 1
using namespace std;
const long long maxn = 3005;
double X[maxn]; //第i个区域的线段长度,是X[r+1]-X[l];
long long cnt[maxn << 2];    //cnt>=0 表示本节点控制的区域下的下位边个数-上位边的个数,cnt==-1,表示本节点的左右子节点的上下位边数不一致
double sum[maxn << 2]; //本节点控制的区域的面积
struct Node
{
    double l, r, h;
    long long d;
    Node() {}
    Node(double a, double b, double c, long long d) : l(a), r(b), h(c), d(d) {}
    bool operator<(const Node &a) const
    {
        return h < a.h;
    }
} node[maxn];
void maintain(long long i, long long l, long long r) //向上维护信息
{
    if (cnt[Ls] == -1 || cnt[Rs] == -1)
        cnt[i] = -1;
    else if (cnt[Ls] != cnt[Rs])
        cnt[i] = -1;
    else
        cnt[i] = cnt[Ls] = cnt[Rs];
    sum[i] = sum[Ls] + sum[Rs];
}
void pushdown(long long i, long long l, long long r) //向下传递信息
{
    long long M = (l + r) >> 1;
    long long &t = cnt[i];
    if (t != -1) //下放cnt信息,并更新sum值
    {
        cnt[Ls] = cnt[Rs] = t;
        sum[Ls] = (t ? (X[M + 1] - X[l]) : 0);
        sum[Rs] = (t ? (X[r + 1] - X[M + 1]) : 0);
    }
}
void build(long long i, long long l, long long r)
{
    if (l == r) //找到叶节点
    {
        cnt[i] = 0;
        sum[i] = 0.0;
        return;
    }
    long long M = (l + r) >> 1;
    build(lson), build(rson);
    maintain(i, l, r);
}
void update(long long ql, long long qr, long long val, long long i, long long l, long long r)
{
    if (ql <= l && qr >= r)
        if (cnt[i] != -1)
        {
            cnt[i] += val;
            sum[i] = (cnt[i] ? (X[r + 1] - X[l]) : 0);
            return;
        }
    pushdown(i, l, r); //更新区间被覆盖的总长度
    long long M = (l + r) >> 1;
    if (ql <= M)
        update(ql, qr, val, lson);
    if (qr > M)
        update(ql, qr, val, rson);
    maintain(i, l, r);
}
long long bing(double key, long long n, double d[])
{
    long long l = 1, r = n;
    while (r >= l)
    {
        long long M = (l + r) >> 1;
        if (d[M] == key)
            return M;
        else if (d[M] > key)
            r = M - 1;
        else
            l = M + 1;
    }
    return -1;
}
int main()
{
    long long q;
    while (scanf("%lld", &q) != EOF)
    {
        if(q==0) {
            printf("*\n");
            break;
        }
        long long n = 0, m = 0;
        while (q--)
        {
            double x1, x2, y1, y2;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            X[++n] = x1; //离散化坐标
            node[++m] = Node(x1, x2, y1, 1);
            X[++n] = x2;
            node[++m] = Node(x1, x2, y2, -1);
        }
        sort(X + 1, X + n + 1);
        sort(node + 1, node + m + 1);
        long long k = 1;
        for (long long i = 2; i <= n; i++) //手动去重&计数
            if (X[i] != X[i - 1])
                X[++k] = X[i];
        build(root); //离散区间[]
        double ret = 0.0;
        for (long long i = 1; i < m; i++)
        {
            long long l = bing(node[i].l, k, X);
            long long r = bing(node[i].r, k, X) - 1;
            if (l <= r)
                update(l, r, node[i].d, root);
            ret += sum[1] * (node[i + 1].h - node[i].h); //sum[1]所有扫描线能有效覆盖的z轴的最大长度
        }
        printf("%.0lf\n", ret);
    }
    return 0;
}

08 A Cache Simulator

 题意是模拟内存的情况,给定一组数据,几个地址的值,一共有64个区块,地址的值都指向这64个区块,如果没有被使用就输出miss,被用过了就输出hit,然后如果是不是原来的值也指向一个原来用过的块也是miss。那么直接模拟就好。

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int main()
{
    char x[10];
    int num=0,cnt=0;
    bool use[70];
    int di[70];
    memset(use,0,sizeof(use));
    while(scanf("%s",x)&&x[2]!='D')
    {
        num++;
        int a=0,now;
        for(int i=0;i<=6;i++)
        {
            if(x[i]>='0'&&x[i]<='9') now=x[i]-'0';
            else if(x[i]>='A'&&x[i]<='F') now=x[i]-'A'+10;
            else if(x[i]>='a'&&x[i]<='f') now=x[i]-'a'+10;
            a=a*16+now;
        }
        int ans=((a/16+1)%64)+1;
       //cout<<a<<" "<<ans<<endl;
        if(use[ans]==0||use[ans]==1&&di[ans]!=a/16+1)
        {
            printf("Miss\n");
            use[ans]=1;
            di[ans]=a/16+1;
        }
        else
        {
            cnt++;
            printf("Hit\n");

        }
    }
    double ans=100*double(cnt)/num;
    printf("Hit ratio = %.2f%%",ans);
}

10 Minimum Distance in a Star Graph

 直接宽搜。

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;

int bfs(int n,string x,string b,int deep)
{
     map<string ,int>ans;
    queue<string >q;
    q.push(x);
    int cnt1=1,cnt2=0;
    while(!q.empty())
    {
        string y=q.front();
        q.pop();
        for(int i=1;i<n;i++)
        {
            string now=y;
            swap(now[0],now[i]);
            if(ans[now]==0)
            {
                ans[now]=deep;
                q.push(now);
                cnt2++;
            }
        }
        cnt1--;
        if(cnt1==0)
        {
            deep++;
            cnt1=cnt2;
            cnt2=0;
        }
    }
    return ans[b];
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {

         string a,b;
        for(int i=1;i<=5;i++)
        {

           cin>>a>>b;

            printf("%d\n",bfs(n,a,b,1));
        }
    }
}

12 The Heaviest Non-decreasing Subsequence Problem

 把权重为5的拆成5个跑最长上升子序列就好。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=10000100;
const int inf = 0x3f3f3f3f;
int a[MAXN],dp[MAXN];//a[n]存序列,dp维护i长序列的最小值
int main()
{
    int n=0,x;
    while(~scanf("%d",&x))
    {
        if(x<0) continue;
        else if(x>=0&&x<10000) a[++n]=x;
        else if(x>10000)
            for(int i=1;i<=5;i++)
                 a[++n]=x-10000;
    }
     int ans;
     memset(dp,inf,sizeof(dp));
    for(int i=1;i<=n;i++)
            *upper_bound(dp+1,dp+n+1,a[i])=a[i];
        ans=lower_bound(dp+1,dp+n+1,inf)-(dp+1);
    printf("%d\n",ans);
}

13 Frequent Subsets Problem

 题目给定m个数组,这些数组里的数都是在n范围内的,又给定一个α,要求有几个子集在所有数组中出现了大于等于α * m次。
 把每个数组中出现大于等于α*m次的数挑出来然后进行暴力找他们每一组的子串,用map存出现次数最后统计即可。

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
map<int, LL>M;
map<LL, LL>M2;
int stand[100][50];
int num[100];
int work[100][50];
int cnt_work[100];
typedef struct
{
    int val;
    int sum;
}Node;
int ans;
void dfs(int dq, LL lss, int zq)
{
    if(cnt_work[dq] == zq)
        return;
    for(int i = zq + 1;i <= cnt_work[dq];i++)
    {
        int ss = work[dq][i];
        LL lsss = lss + (1<<ss);
//        cout<<lss<<endl;
        M2[lsss]++;
        dfs(dq, lsss, i);
    }
}
int main()
{
    M.clear();
    M2.clear();
    int N;
    double s;
    cin>>N>>s;
    int ls;
    int cntt = 0;
    while(scanf("%d", &ls) != EOF)
    {
        stand[++cntt][1] = ls;
        num[cntt] = 1;
        M[ls]++;
        while(getchar() != '\n')
        {
            scanf("%d", &ls);
            M[ls]++;
            stand[cntt][++num[cntt]] = ls;
        }
    }
    for(int i = 1;i <= cntt;i++)
    {
        cnt_work[i] = 0;
        for(int j = 1;j <= num[i];j++)
        {
            if(M[stand[i][j]] >= (LL)ceil((double)cntt * s * 1.0))
            {
                work[i][++cnt_work[i]] = stand[i][j];
            }
        }
    }
    for(int i = 1;i <= cntt;i++)
    {
        LL lss = 0;
        dfs(i, lss, 0);
    }
    map<LL,LL>::iterator it;
    it = M2.begin();
    LL ans = 0;
    while(it != M2.end())
    {
        //it->first;
        if(it->second >= (LL)ceil((double)cntt * s * 1.0))
            ans++;
        it ++;
    }
    printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值