5.13考试整理

5.13五一清北基础班试题

1、洛谷P1149 火柴棒等式

时空限制1s / 128MB

题目描述

给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:

注意:

1.加号与等号各自需要两根火柴棍

2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)

   3.n根火柴棍必须全部用上

输入输出格式

输入格式:

输入文件matches.in共一行,又一个整数n(n<=24)。

输出格式:

输出文件matches.out共一行,表示能拼成的不同等式的数目。

输入输出样例

输入样例#1:

样例输入1:

14

样例输入2:

18

输出样例#1:

样例输出1:

2

样例输出2:

9

说明

【输入输出样例1解释】

2个等式为0+1=1和1+0=1。

【输入输出样例2解释】

9个等式为:

0+4=4     0+11=11    1+10=11

2+2=4     2+7=9      4+0=4

7+2=9     10+1=11    11+0=11

思路:

  搜索,如果找到满足条件的ans++,

  其实我的本意是打表的,敲了一个看似正确的代码出来,但是是真的不敢用(怕超时)……,所以交了打表代码上去(竟然奇迹般的过了……)

打表代码=v=:

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    int cc;
    scanf("%d",&cc);
    switch(cc)
    {
        case 0 :
        case 1 :
        case 2 :
        case 3 :
        case 4 :
        case 5 :
        case 6 :
        case 7 :
        case 8 :
        case 9 :
        case 10 :
        case 11 :
        case 12 :
            printf("0");
            break; 
        case 13 :
            printf("1");
            break;
        case 14 :
            printf("2");
            break;
        case 15 :
            printf("8");
            break;
        case 16 :
            printf("9");
            break;
        case 17 :
            printf("6");
            break;
        case 18 :
            printf("9");
            break;
        case 19 :
            printf("29");
            break;
        case 20 :
            printf("39");
            break;
        case 21 :
            printf("38");
            break;
        case 22 :
            printf("65");
            break;
        case 23 :
            printf("88");
            break;
        case 24 :
            printf("128");
            break;
    }
    return 0;
}
打表

而另外一种就是正解啦!

(搜索!看着其实是挺像暴力的hh)

正解代码=u=:

#include <iostream>
using namespace std;

int QAQ[10]= {6,2,5,5,4,5,6,3,7,6}; //存放每个数字所需要的火柴棒数
int x,y,k,n;

int qwq(int n) { //进行判断是否满足条件
    int q=0;
    do {
        q=q+QAQ[n%10]; //取出个位数,进行判断需要使用多少根火柴棒
        n=n/10; //继续进行下去
    } while(n);
    return q; //用来计数
}

int main() {
    cin>>n;
    for(x=0; x<=1000; x++)
        for(y=0; y<=1000; y++)
            if(qwq(x)+qwq(y)+qwq(x+y)==n-4)
                k++;
    cout<<k;
    return 0;
}
View Code

2、洛谷P1113 杂务

题目描述

John的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务1。John有需要完成的n个杂务的清单,并且这份清单是有一定顺序的,杂务k(k>1)的准备工作只可能在杂务1..k-1中。

写一个程序从1到n读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定John的农场有足够多的工人来同时完成任意多项任务。

输入输出格式

输入格式:

1行:一个整数n,必须完成的杂务的数目(3<=n<=10,000);

2 ~ n+1行: 共有n行,每行有一些用1个空格隔开的整数,分别表示:

工作序号(1..n,在输入文件中是有序的);

完成工作所需要的时间len(1<=len<=100);

   一些必须完成的准备工作,总数不超过100个,由一个数字0结束。有些杂务没有需要准备的工作只描述一个单独的0,整个输入文件中不会出现多余的空格。

输出格式:

一个整数,表示完成所有杂务所需的最短时间。

输入输出样例

输入样例#1:

7

1 5 0

2 2 1 0

3 3 2 0

4 6 1 0

5 1 2 4 0

6 8 2 4 0

7 4 3 5 6 0

输出样例#1:

23

思路(雾):

  一看到这道题,我就不自觉地想起了拓扑排序!

  额……对于如此,能够想到方法毕竟还是好的嘛!

  所以抓紧时间的敲了一份拓扑排序(自认为是非常正确的!),可是现实是血淋淋的……,

  爆零了耶……可怕……

代码(雾):

(出错在哪里了呢…其实这可能是我最最最长的一份代码…)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdlib>

using namespace std;

const int M = 10005;
int n;//3 <= n <= 10,000
int ans;
int que[M],H[M];
int deg[M];
int now;
int fg;

struct B{
    int num;
    int len;
    int nxt;
    int vv;
    int cengshu;
//杂务k(k>1)的准备工作只可能在杂务1..k-1中
}v[M]; 

void Ins(int u, int vv, int w)//邻接表 
{
    ++now;
    v[now].vv = vv;
    v[now].len = w;
    v[now].nxt = H[u];
    H[u] = now;
}

void TO()
{
    int h,t,i,j;
    for (i = 1; i <= n; i ++)
        for (j = H[i]; j != -1; j = v[j].nxt)
        {
            int vx = v[j].vv;
            deg[vx] ++;
        }

    h = t = 0; 
    for (i=1;i<=n;i++)
    {
        if (deg[i]) continue;
        que[t] = i; t ++;
        if(v[i].len > ans) ans=v[i].len;
    }

    int nowans=ans,nowceng=2;
    for (;h < t;h++)
    {
        int u = que[h];//队头元素 
        if(v[u].cengshu != nowceng)
        {
            nowceng++;
            nowans=ans;
        }
        
        int aa=0;
        for (i = H[u]; i != -1; i = v[i].nxt)
        {
            int vq = v[i].vv;
            deg[vq] --;//删边
            aa++;
            if(aa==1)
            {
                if(nowans+v[vq].len > ans) ans=v[vq].len+nowans;
            }
            if (deg[vq] == 0)
            {
                que[t] = vq;
                t ++;
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    int qm,numm,lenm;
    for(int i=1;i<=n;i++) H[i]=-1; 
    int cc;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&numm,&lenm);//编号(应该)是1-n顺下来的
        cc=0;
        while(scanf("%d",&qm) == 1)
        {
            if(qm == 0)
            {
                break;
            }
            Ins(numm,qm,lenm);//numm连接的下一条边是qm 
            cc++;
        }
        switch(cc)
        {
            case 0 : v[i].cengshu=1;break;
            case 1 : v[i].cengshu=2;break;
            case 2 : v[i].cengshu=3;break;
            case 3 : v[i].cengshu=4;break;
            case 4 : v[i].cengshu=5;break;
            case 5 : v[i].cengshu=6;break;
            case 6 : v[i].cengshu=7;break;
            case 7 : v[i].cengshu=8;break;
            case 8 : v[i].cengshu=9;break;
            case 9 : v[i].cengshu=10;break;
            case 10 : v[i].cengshu=11;break;
            case 11 : v[i].cengshu=12;break;
            case 12 : v[i].cengshu=13;break;
            case 13 : v[i].cengshu=14;break;
            case 14 : v[i].cengshu=15;break;
            case 15 : v[i].cengshu=16;break;
            case 16 : v[i].cengshu=17;break;
            case 17 : v[i].cengshu=18;break;
            case 18 : v[i].cengshu=19;break;
            case 19 : v[i].cengshu=20;break;
            case 20 : v[i].cengshu=21;break;
            case 21 : v[i].cengshu=22;break;
            case 22 : v[i].cengshu=23;break;
            case 23 : v[i].cengshu=24;break;
            case 24 : v[i].cengshu=25;break;
            case 25 : v[i].cengshu=26;break;
            case 26 : v[i].cengshu=27;break;
            case 27 : v[i].cengshu=28;break;
            case 28 : v[i].cengshu=29;break;
            case 29 : v[i].cengshu=30;break;
            case 30 : v[i].cengshu=31;break;
            case 31 : v[i].cengshu=32;break;
            case 32 : v[i].cengshu=33;break;
            case 33 : v[i].cengshu=34;break;
            case 34 : v[i].cengshu=35;break;
            case 35 : v[i].cengshu=36;break;
            case 36 : v[i].cengshu=37;break;
            case 37 : v[i].cengshu=38;break;
            case 38 : v[i].cengshu=39;break;
            case 39 : v[i].cengshu=40;break;
            case 40 : v[i].cengshu=41;break;
            case 41 : v[i].cengshu=42;break;
            case 42 : v[i].cengshu=43;break;
            case 43 : v[i].cengshu=44;break;
            case 44 : v[i].cengshu=45;break;
            case 45 : v[i].cengshu=46;break;
            case 46 : v[i].cengshu=47;break;
            case 47 : v[i].cengshu=48;break;
            case 48 : v[i].cengshu=49;break;
            case 49 : v[i].cengshu=50;break;
            case 50 : v[i].cengshu=51;break;
            case 51 : v[i].cengshu=52;break;
            case 52 : v[i].cengshu=53;break;
            case 53 : v[i].cengshu=54;break;
            case 54 : v[i].cengshu=55;break;
            case 55 : v[i].cengshu=56;break;
            case 56 : v[i].cengshu=57;break;
            case 57 : v[i].cengshu=58;break;
            case 58 : v[i].cengshu=59;break;
            case 59 : v[i].cengshu=60;break;
            case 60 : v[i].cengshu=61;break;
            case 61 : v[i].cengshu=62;break;
            case 62 : v[i].cengshu=63;break;
            case 63 : v[i].cengshu=64;break;
            case 64 : v[i].cengshu=65;break;
            case 65 : v[i].cengshu=66;break;
            case 66 : v[i].cengshu=67;break;
            case 67 : v[i].cengshu=68;break;
            case 68 : v[i].cengshu=69;break;
            case 69 : v[i].cengshu=70;break;
            case 70 : v[i].cengshu=71;break;
            case 71 : v[i].cengshu=72;break;
            case 72 : v[i].cengshu=73;break;
            case 73 : v[i].cengshu=74;break;
            case 74 : v[i].cengshu=75;break;
            case 75 : v[i].cengshu=76;break;
            case 76 : v[i].cengshu=77;break;
            case 77 : v[i].cengshu=78;break;
            case 78 : v[i].cengshu=79;break;
            case 79 : v[i].cengshu=80;break;
            case 80 : v[i].cengshu=81;break;
            case 81 : v[i].cengshu=82;break;
            case 82 : v[i].cengshu=83;break;
            case 83 : v[i].cengshu=84;break;
            case 84 : v[i].cengshu=85;break;
            case 85 : v[i].cengshu=86;break;
            case 86 : v[i].cengshu=87;break;
            case 87 : v[i].cengshu=88;break;
            case 88 : v[i].cengshu=89;break;
            case 89 : v[i].cengshu=90;break;
            case 90 : v[i].cengshu=91;break;
            case 91 : v[i].cengshu=92;break;
            case 92 : v[i].cengshu=93;break;
            case 93 : v[i].cengshu=94;break;
            case 94 : v[i].cengshu=95;break;
            case 95 : v[i].cengshu=96;break;
            case 96 : v[i].cengshu=97;break;
            case 97 : v[i].cengshu=98;break;
            case 98 : v[i].cengshu=99;break;
            case 99 : v[i].cengshu=100;break;
            case 100 : v[i].cengshu=101;break;
        }
    }

    TO();

    printf("%d",ans);

    return 0;
}
不要问我为什么打了100多行表……

慌张跑去问大佬!大佬给出的代码是这样的——

代码(真):

#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

const int M = 10005;
int n,ans; //ans记录答案 
int t[M]; //储存时间 
bool v[M][M]; //记录是否有边 
int f[M]; //更新状态 
int r[M]; //储存准备工作 

queue<int>q;

void TOPO()
{
    for(int i=1;i<=n;++i)
    {
        if(r[i] == 0)
        {
            q.push(i);
            f[i]=t[i]; 
//            进行初始化,最早完成当前工作的时间就是自己本身完成所需要的时间
        }
    }

    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=1;i<=n;++i)
        {
            if(v[u][i])
            {
                --r[i];//删边 
                if(r[i] == 0)
                {
                    q.push(i);//入队(一层一层的来) 
                }
                f[i]=max(f[i],f[u]+t[i]);
//                转移方程(用以前已经更新过的更新当前时间) 
            }
        }
    }
    for(int i=1;i<=n;++i)
    {
        ans=max(ans,f[i]); 
//        因为标号最大的有可能不是花时间最多的,所以从中找出花时间最多的即为答案 
    }
}

/*
7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0
*/

int main()
{
    scanf("%d",&n);
    int num,len,c;
    for(int i=1;i<=n;++i)
    {
//        scanf("%d%d%d",&num,&len,&c);
        scanf("%d%d",&num,&len);
        t[num]=len;
//        while(c != 0)
        while(scanf("%d",&c)&&c) //只有当读入的c非零的时候进行接下来的操作 
        {
            ++r[num];//需要的准备工作++ 
            v[c][num]=true;//标记做完c工作之后才能做num工作 
//            scanf("%d",&c);
        }
        
    }

    TOPO();

    printf("%d",ans);

    return 0;
}
TOPO

正确思路:

  在进入每一层时,都求出到达这个点的最大时间.(因为我们要保证所有的任务都完成!)

  然后一层一层的进行更新,最后取出最大值,就是最早完成的时间.(疑似动规?)


3、洛谷P2782 友好城市

题目描述

有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。没对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。

输入输出格式

输入格式:

1行,一个整数N(1<=N<=5000),表示城市数。

2行到第n+1行,每行两个整数,中间用一个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0<=xi<=10000)

输出格式:

仅一行,输出一个整数,表示政府所能批准的最多申请数。

输入输出样例

输入样例#1:

7

22 4

2 6

10 3

15 12

9 8

17 17

4 2

输出样例#1:

4

说明

1<=N<=5000,0<=xi<=10000

思路:

  因为是说建造最多多少航道才能够不重复,所以将给出的南岸坐标(连带着北岸)进行排序,如果找到最长的上升子序列,那么就是最多能够建造的航道.

巧妙的转化代码酱=u=

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdlib>

using namespace std;
//思路:根据南岸的坐标排好序之后,寻找北岸的最长上升子序列

const int M = 5005;
int n; //5000
int f[M];

struct A{
    int nx;
//0<=xi<=10000
    int bx;
    bool operator < (const A &q ) const
    {
        return nx < q.nx;
    }
}zb[M];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&zb[i].nx,&zb[i].bx);
    }

    sort(zb+1,zb+1+n);

    f[1]=1;
    for(int i=2;i<=n;i++)//第一个点的上升子序列一定为1(because 前面没有数) 
    {
        for(int j=1;j<=i-1;j++)//通过前面已经找好了的序列更新当前序列
            if(zb[i].bx > zb[j].bx && f[i] < f[j])//求上升子序列
                f[i]=f[j];
        f[i]++;        
    }

    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        if(f[i]>maxx) maxx=f[i];
    }

    printf("%d",maxx);

    return 0;
}
友好城市

 


考试小结:

(以为会100+100+100果然是想多了……AK遥远……啧啧)

真实分数(100+0+100)

对于中间的零,我无话可说……错了就是错了,我需要找出自己错在哪里的!

第二题我的想法是topo+乱搞(还想了一种挺厉害的方法!可惜无法实现……直到大佬告诉我原来开[10005][10005]的数组能够AC,感觉特失望……,我本来不想写邻接表,因为我只是背过代码,具体意思一直是没有搞明白的.

所以呢,这告诉我们一定要写自己会的,认为绝对正确的!

不能够盼望着瞎猫碰上死耗子什么的,但是多了一分技巧就多一分把握!所以要搞懂邻接表!)

还有就是骗分过样例之后,应该自己再造几组数据!第二题就是过了样例草草上交...

posted @ 2017-05-13 20:38  夜雨声不烦  阅读(209)  评论(0编辑  收藏  举报