第四届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

****************************************************************/

  

 

 

你可能感兴趣的:(程序设计)