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; }
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; }
慌张跑去问大佬!大佬给出的代码是这样的——
代码(真):
#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; }
正确思路:
在进入每一层时,都求出到达这个点的最大时间.(因为我们要保证所有的任务都完成!)
然后一层一层的进行更新,最后取出最大值,就是最早完成的时间.(疑似动规?)
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,感觉特失望……,我本来不想写邻接表,因为我只是背过代码,具体意思一直是没有搞明白的.
所以呢,这告诉我们一定要写自己会的,认为绝对正确的!
不能够盼望着瞎猫碰上死耗子什么的,但是多了一分技巧就多一分把握!所以要搞懂邻接表!)
还有就是骗分过样例之后,应该自己再造几组数据!第二题就是过了样例草草上交...