zoukankan      html  css  js  c++  java
  • LETTers比赛第一场 解题报告

    解题报告

    提交人:蔡驰宇

    提交日期:2012.04.11

    第1题解题报告

    题目描述

    题目提供的Fibonacci的递推公式,以及相应的初值,要求第n个Fibonacci数。

    题面建模

    由Fibonacci递推公式和测试数据可知int型与_64int型数据无法满足题目求解要求,因而要使用高精度算法,即为大数问题,利用数组来进行计算。

    解题要点

    字符串与数组之间的转换,大数数组的基本运算方法。

    时空开销分析

    特别说明

    程序

    #include <iostream>

    #include <string>

    using namespace std;

    int n;

    int f[5][2100];

    void init()

    {

        memset(f, 0, sizeof(f));

        f[0][0] = 1;

        f[1][0] = 1;

        f[2][0] = 1;

        f[3][0] = 1;

        n--;

    }

    int fib()

    {

        if(n < 4) return 1;

        int i, j, r, t, m;

        for(i=4, m=1; i<=n; i++)

        {

            for(j=0, r=0; j<m; j++)

            {

                t = f[(i-1)%5][j]+f[(i-2)%5][j]+f[(i-3)%5][j]+f[(i-4)%5][j] + r;

                f[i%5][j] = t % 10;

                r = t / 10;

            }

            if(r > 0)

            {

                f[i%5][j] = r;

                m++;

            }

        }

        return m;

    }

    void display(int m)

    {

        int j;

        for(j=m-1; j>=0; j--)

        {

            printf("%d", f[n%5][j]);

        }

        printf("\n");

    }

    int main()

    {

        while(scanf("%d", &n) != EOF)

        {

            init();

            int m = fib();

            display(m);

        }

        return 0;

    }

    第2题解题报告

    提交人:蔡驰宇

    提交日期:2012.04.11

    题目描述

    题目给定三个字符串,判断前两个字符串是否能够按题所述的规则组合成第三个字符串。

    题面建模

    题意简化后可以很明显的看出是一个DFS问题,在使用DFS的同时还要结合记忆化搜索的方法。

    解题要点

    时空开销分析

    特别说明

    本题也可以使用BFS算法。

    程序

    #include <iostream>

    using namespace std;

    bool flag, hash[205][205];

    int len, len1, len2;

    char s[405], s1[205], s2[205];  

    void dfs (int i, int j, int k)  //字符串匹配型深搜,s1[i]和s2[j]分别跟s[k]匹配

    {

        if (flag)

            return ;

        if (k == len)    //匹配成功

        {

            flag = true;

                  return ;

        }

       if (hash[i][j]) //hash法记忆状态,若状态再次出现则已经不可能匹配成功,记忆化搜索

            return ;

        hash[i][j] = true;

        if (!flag && s1[i] == s[k])

            dfs (i+1, j, k+1);

        if (!flag && s2[j] == s[k])

            dfs (i, j+1, k+1);

    }

    int main()

    {

        int t, x = 1;

        scanf ("%d", &t);

        while (t--)

        {

            scanf ("%s%s%s", s1, s2, s);

            len1 = strlen(s1);

            len2 = strlen(s2);

            len = strlen(s);

            memset (hash, false, sizeof(hash));

            flag = false;

            dfs (0, 0, 0);

            printf ("Data set %d: ", x++);

            if (flag)

                printf ("yes\n");

            else printf ("no\n");

        }

        return 0;

    }

    第3题解题报告

    提交人:蔡驰宇

    提交日期:2012.04.11

    题目描述

    给一个字母锁,含有n个字母,然后给定m个区间,并规定区间里面的那一段字母是可以同时改变的,比如a变为b,b变为c,z变为a之类的,然后如果锁可以通过有限次变换变成相同的,就规定为同一把锁。然后要求有多少把不同的索。

    题面建模

    首先确认下如果没有这种区间存在,那么锁的种类总共有26^n个,而出现了一个区间n就得减去1,因为无论是在哪个区间,出现了一个区间,就代表这个区间有26种相同的排列组合要排除掉。结果就由原来的26^n变为了现在的26^(n-1)。

    解题要点

    通过并查集的方法来生成最小树,从而可以得出结果。

    时空开销分析

    特别说明

    在设计程序时需要注意一种特殊情况,就是比如有一个区间1~5,还有一个区间1~2,那么就等于隐含了一个存在的区间3~5,因为区间3~5可以由前两个区间生成。

    程序

    #include<iostream>

    using namespace std;

    const int MAX = 10000005;

    const int MOD = 1000000007;

    typedef struct set

    {

        int parent;

    } S;

    S set[MAX];

    int findParent(int x)

    {

        if(x != set[x].parent)

            set[x].parent = findParent(set[x].parent);

        return set[x].parent;

    }

    int Union(int x, int y)

    {

        x = findParent(x);

        y = findParent(y);

        if(x == y)

            return 0;

        //if(set[x].rank < set[y].rank)

        {

            set[x].parent = y;

        }

        /*else

        {

               set[y].parent = x;

               if(set[y].rank == set[x].rank)

                      set[x].rank++;

        }*/

        return 1;

    }

    void makeSet()

    {

        for(int i = 0; i < MAX; i++)

        {

            set[i].parent = i;

            //set[i].rank = 0;

        }

    }

    __int64 Exp(__int64 a, __int64 x)//二分求幂

    {

        __int64 b;

        if(x == 0)

            return 1;

        b = Exp(a, x / 2);

        b = b * b % MOD;

        if(x & 1)

            b = b * 26 % MOD;

        return b;

    }

    int main(void)

    {

        int n, m;

        while(scanf("%d %d", &n, &m) == 2)

        {

            makeSet();

            int ans = 0;

            for(int i = 0; i < m; i++)

            {

                int s, e;

                scanf("%d %d", &s, &e);

                ans += Union(s, e + 1);

            }

            printf("%I64d\n", Exp((__int64)26, (__int64)(n - ans)));

        }

        return 0;

    }

    第4题解题报告

    提交人:蔡驰宇

    提交日期:2012.04.11

    题目描述

    有n个人要去聚会,然后这些人都是一个公司的,有上下司关系,要求邀请最多的人,并且这些人之间没有从属关系。并且在最后要判断结果是否唯一。

    题面建模

    建一个n节点的关系数,每个节点代表一个人。从中选择一些点,使这些点均不存在亲子关系,最多能取多少个点,并且判断取法是否唯一。

    解题要点

    树状DP+一个判断。设dp[i][0]为在以i为根的子树中,不选择点i最多能够选的数目,dp[i][1]为选择i点的最多数目。

    状态转移方程:

    当i为叶子节点时:

    dp[i][0]=0;

    dp[i][1]=1;

    当i为非叶子节点时:

    dp[i][0]=sum(max(dp[j][0],dp[j][1])) (j为i的儿子)

    dp[i][1]=sum(dp[j][0]) (j为i的儿子)

    时空开销分析

    特别说明

    解的唯一性的判断:

    设u[i][x]为0时表示dp[i][x]的解唯一,为1则表示不唯一.

    当x为0时,若存在j是i的儿子,使得dp[j][0]>dp[j][1]且u[j][0]=1,或dp[j][0]<dp[j][1]且u[j][1]=1或dp[j][0]=dp[j][1],则u[i][0]=1;

    当x为1时,若存在j是i的儿子,使得u[j][0]=1,则u[i][0]=1;

    程序

    #include<stdio.h>

    #include<string.h>

    #define MAXN 205

    struct Node

    {

        char name[105];

        Node *next;

    }node[MAXN];

    struct List

    {

        int node;

        List *next;

    }head[MAXN];

    int dp[MAXN][2],u[MAXN][2];

    void DP(int node)

    {

        List *p;

        int sumdp=0;

        if (head[node].next==NULL)

        {

            dp[node][0]=0;

            dp[node][1]=1;

            u[node][0]=0;

            u[node][1]=0;

        }

        else

        {

            p=head[node].next;

            while (p!=NULL)

            {

               DP(p->node);

                if (dp[p->node][0]>dp[p->node][1])

                {

                    sumdp+=dp[p->node][0];

                    if (u[p->node][0]==1) u[node][0]=1;

                         }

                else

                if (dp[p->node][0]<dp[p->node][1])

                {

                   sumdp+=dp[p->node][1];

                    if (u[p->node][1]==1) u[node][0]=1;

                }

                else

                {

                    sumdp+=dp[p->node][0];

                    u[node][0]=1;

                }

                dp[node][1]+=dp[p->node][0];

                if (u[p->node][0]==1) u[node][1]=1;

                p=p->next;

                  }

           dp[node][0]=sumdp;

            dp[node][1]+=1;

        }

    }

    int main()

    {

        List *s;

        int i,j,n;

        char s1[MAXN][105],s2[MAXN][105];

        while (scanf("%d",&n)&&n)

        {

            memset(dp,0,sizeof(dp));

            memset(u,0,sizeof(u));

            memset(s1,0,sizeof(s1));

            memset(s2,0,sizeof(s2));

            for (i=0;i<=n;++i) head[i].next=NULL;

            getchar();

            scanf("%s",node[0].name);

            getchar();

            for (i=1;i<n;++i)

            {

                scanf("%s %s",s1[i],s2[i]);

                getchar();

                strcpy(node[i].name,s1[i]);

            }

            for (i=1;i<n;++i)

            {

                for (j=0;j<n;++j)

                {

                    if (strcmp(s2[i],node[j].name)==0)

                    {

                        s=new List;

                        s->node=i;

                        s->next=head[j].next;

                        head[j].next=s;

                        break;

                    }

                }

            }

            DP(0);

            if (dp[0][0]>dp[0][1])

            {

                printf("%d ",dp[0][0]);

                if (u[0][0]) printf("No\n");

                else printf("Yes\n");

            }

            else

            if (dp[0][0]<dp[0][1])

            {

                printf("%d ",dp[0][1]);

                if (u[0][1]) printf("No\n");

                else printf("Yes\n");

            }

            else

            printf("%d No\n",dp[0][0]);

        }

        return 0;

    }

  • 相关阅读:
    table拖动列宽
    解决 wm_concat函数 长度不够问题
    「Luogu」[JSOI2007]字符加密 解题报告
    Markdown数学符号
    「P5004」专心OI
    「CF242E」XOR on Segment 解题报告
    「CF86D」Powerful array 解题报告
    「USACO08JAN」电话线Telephone Lines 解题报告
    「Luogu P2015」二叉苹果树 解题报告
    「Luogu P3866」[TJOI2009]战争游戏 解题报告
  • 原文地址:https://www.cnblogs.com/LETTers/p/2442975.html
Copyright © 2011-2022 走看看