第四届ACM_DIY群程序设计竞赛 (部分解题报告) 弱菜在此大牛无视。。。

http://ac.jobdu.com/problem.php?pid=1421

第一题:题意就是给定n个点每个点可能带表Female或者Male,以及给出各个节点的关系矩阵,让你求出现 AbOr的期望,  、

AbOr这样定义:

1:必须是Male;

2:他至少有m个Female朋友;

刚开始我一直以为求的是AbOr出现的概率,所以显示按每个节点两种状态(F ,M)爆搜所有可能的情况然后除以总的可能(2^N)样例竟然都过了,提交直接TLE因为本菜没有注意到T = 10000 这样复杂度就成了10^4*2^20了,指定超时。后来想到了循环每个节点,然后检查他的哦鞥有节点只有他的朋友节点大于m 才有可讨论性,假设他的朋友节点为ct个,那么他所有的可能是 c(ct,m) ,c(ct,m + 1) , ct(ct,m + 2) , ...... , c(ct,ct);而他的概率全都是 (1/2)(当前节点肯定是M)*(1/2^i) *(1/2^(ct - i)) (m<=i <= ct) 及概率p = 1/2^(ct+1);而且每个情况得概率相同。这样再根据期望公式  E(X) = X1*p(X1) + X2*p(X2) + …… + Xn*p(Xn)求即可:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxn 55
using namespace std;
 
int pow2[maxn];
double c[maxn][maxn];
int n,m;
char str[maxn][maxn];
 
int main()
{
    int i,j,t;
    //求2的幂
    for (i = 0; i < 21; ++i)
    pow2[i] = 1<<i;
    //求组合
    for (i = 0; i < 21; ++i)
    c[i][i] = c[i][0] = 1;
    for (i = 2; i < 21; ++i)
    {
        for (j = 1; j < i; ++j)
        {
            c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
        }
    }
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        for (i = 0; i < n; ++i) scanf("%s",str[i]);
        if (n ==0)
        {
            printf("0.00\n");
            continue;
        }
        double sum = 0,ans = 0;
        for (i = 0; i < n; ++i)
        {
            int ct = 0; sum = 0;
            //遍历他的朋友
            for (j = 0; j < n; ++j)
            {
                if (str[i][j] == '1') ct++;
            }
            if (ct >= m)
            {
                //求和后乘以概率
                for (int k = m; k <= ct; ++k)
                {
                    sum += c[ct][k];
                }
                ans += (1.0/pow2[ct + 1])*sum;
            }
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1421
    User: gbaoxing
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1536 kb
****************************************************************/

  http://ac.jobdu.com/problem.php?pid=1422

第二题:

这道题啊,问了虎哥才做出来的,分别开两个数组记录当前节点左边比他小的最近位置,右边比他小的最近位置,然后比较左右距离大小输出即可;

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxn 1000009
using namespace std;
 
int a[maxn],l[maxn],r[maxn];
int n;
int Abs(int x)
{
    if (x < 0) return -x;
    else return x;
}
int main()
{
    int i,t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        scanf("%d",&a[1]);
        //查找左边的最近的比他小的位置
        l[1] = 0;
        for (i = 2; i <= n; ++i)
        {
            scanf("%d",&a[i]);
            int pos = i - 1;
            while (a[pos] >= a[i])
            {
                pos = l[pos];
                if (pos == 0) break;
            }
            if (pos == 0) l[i] = 0;
            else l[i] = pos;
        }
        //查找右边的最近的比他小的位置
        r[n] = 0;
        for (i = n - 1; i >= 1; --i)
        {
            int pos = i + 1;
            while (a[pos] >= a[i])
            {
                pos = r[pos];
                if (pos == 0) break;
            }
            if (pos == 0) r[i] = 0;
            else r[i] = pos;
        }
        //遍历输出
        for (i = 1; i < n; ++i)
        {
            if (l[i] !=0 && r[i] != 0)
            {
                int t;
                if (Abs(l[i] - i) <= Abs(r[i] - i)) t = l[i];
                else t = r[i];
                printf("%d ",a[t]);
 
            }
            else
            {
                if (l[i] == 0 && r[i] == 0) printf("0 ");
                else
                {
                    if (l[i] != 0)
                    printf("%d ",a[l[i]]);
                    else
                    printf("%d ",a[r[i]]);
                }
            }
        }
         if (l[n] !=0 && r[n] != 0)
         {
                int t;
                if (Abs(l[n] - n) <= Abs(r[n] - n)) t = l[n];
                else t = r[n];
                printf("%d",a[t]);
 
         }
        else
        {
                if (l[n] == 0 && r[n] == 0) printf("0");
                else
                {
                    if (l[n] != 0)
                    printf("%d",a[l[n]]);
                    else
                    printf("%d",a[r[n]]);
                }
        }
        printf("\n");
    }
   return 0;
}
 
/**************************************************************
    Problem: 1422
    User: gbaoxing
    Language: C++
    Result: Accepted
    Time:1610 ms
    Memory:13228 kb
****************************************************************/

  第四题:http://ac.jobdu.com/problem.php?pid=1424

题意是给定n个圆,m个描述,x y表示编号为x的圆要套y个圆,题目给出如果重复嵌套只算最外层的嵌套。这道题目trick大大的多,首先看

1:1≤n≤16,0≤m≤100  这里m可能远大于n所以会出现 形如下面的数据

1 2 

1 4

1 6 这样不确定的话输出NO 

如果是:

1 2

1 2 的重复数据要记得去重;

2:. (1≤x≤n,|y|≤1000)y还有可能负值,并且有可能大于 n - 1

所以如果出现这样的数据也指定不可能了。

才开始我使用两个栈来模拟的,s1放需要套圆的圆(即y != 0) s2放不需要套圆的圆(即y ==0) 每次从s2中取y个给s1中的圆套,这样就满足了,然后s1的那个出栈,y ==0 压入s2变为可被套的、、知道s2为空即可,我在处理向阳里给的第三组数数据时,直接从m 到 n处理未给定的节点了,其实应该从s1.size() + s2.size()开始的,改后总算A了,整死我了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>
#define maxn 108
using namespace std;
 
struct node
{
    int x;
    int num;
}stock[maxn];
stack<node>s1,s2;
int n,m,len;

int isok(node z)
{
    for (int i = 0; i < len; ++i)
    {
        if (stock[i].x == z.x && stock[i].num != z.num) return -1;//判断trick
        if (stock[i].x == z.x && stock[i].num == z.num) return 0;//去重
    }
    stock[len++] = z;
    return 1;
}
int main()
{
    int i,t;
    scanf("%d",&t);
    while (t--)
    {
        len = 0;
        while (!s1.empty()) s1.pop();
        while (!s2.empty()) s2.pop();
        scanf("%d%d",&n,&m);
        node p;
        bool flag = false;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d",&p.x,&p.num);
            int mark = isok(p);
            if (mark == -1) flag = true;
            else if (mark == 1)
            {
                if (p.num) s1.push(p);
                else s2.push(p);
            }
            if (p.num > n - 1 || p.num < 0)
            flag = true;
        }
        if (flag)
        {
            printf("NO\n");
            continue;
        }
        //注意起点。。
        for (i = s1.size() + s2.size(); i < n; ++i)
        {
            p.num = 0;
            s2.push(p);
        }
        //两个栈的模拟
        while (!s1.empty() && !s2.empty())
        {
            node tmp = s1.top();  s1.pop();
            if (tmp.num > s2.size())
            {
                flag = true;
                break;
            }
            else
            {
                for (i = 0; i < tmp.num; ++i)
                {
                    s2.pop();
                }
                tmp.num = 0;
                s2.push(tmp);
            }
        }
        if (s1.empty() && !flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
 
/**************************************************************
    Problem: 1424
    User: gbaoxing
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1516 kb
****************************************************************/

  其实还有一个更容易的办法就是判完trick后,把所有满足条件并且去重之后的y相加,判断是否<= n -1 如果成立YES 否则NO 不知道怎么证明:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>
using namespace std;
 
struct node
{
    int x;
    int y;
}p[108];
int n,m,len;
 
int isok(node z)
{
    for (int i = 0; i < len; ++i)
    {
        if (p[i].x == z.x && p[i].y != z.y) return -1;
        if (p[i].x == z.x && p[i].y == z.y) return 1;
    }
    p[len++] = z;
    return 0;
}
 
int main()
{
    int i,t;
    int x,y;
    scanf("%d",&t);
    while (t--)
    {
        len = 0;
        scanf("%d%d",&n,&m);
        bool flag = false;
        node q;
        int ct = 0;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d",&x,&y);
            q.x = x; q.y = y;
            int mark = isok(q);
            if (mark == -1) flag = true;
            else if (mark == 0) ct += y;
            if (y > n - 1 || y < 0)
            flag = true;
 
        }
        if (flag)
        {
            printf("NO\n");
            continue;
        }
        if (ct <= n - 1)  printf("YES\n");
        else   printf("NO\n");
    }
    return 0;
}
 
/**************************************************************
    Problem: 1424
    User: gbaoxing
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1512 kb
****************************************************************/

  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值