【测试】11月9日的测试
整体分析
1(集合删数)
题目大意
问题描述:
一个集合有如下元素:1是集合元素;若P是集合的元素,则2 * P +1,4*P+5也是集合的元素,取出此集合中最小的K个元素,按从小到大的顺序组合成一个多位数,现要求从中删除M个数位上的数字,使得剩下的数字最大,编程输出删除前和删除后的多位数字。
注:不存在所有数被删除的情况`
输入格式:
输入的仅一行,K,M的值,K,M均小于等于30000。
输出格式:
输出为两行,第一行为删除前的数字,第二行为删除后的数字。
样例输入:
5 4
样例输出:
137915
95
用到的数据结构,算法
贪心,字符串处理,打表一类的……
正确分析
首先要产生这个集合,可以打表,也可以先有现用的数组里的数字产生。每次的元素只有可能有已有的元素通过两种运算产生,所以我们每次产生两个元素,取其小者即可。接下来就是贪心策略的使用了,显然要去找比较大的元素,那么我们为了满足删除一部分数之后,剩下的数能满足要求,那么每个数的取值是被限制在产生的数的一个确定的区间中的。每次在选取一个数后,我们就将区间起点移动到这个数的位置,区间的尾端只和选取的数的个数有关。那么通过n-m次的选取,我们就会得到一个最大值
错误原因
打表时出现错误。打的表不够大,没有选取目标元素。
贪心策略不是很优秀,效率较低。
反思
在打表时,有的时候要涉及到排序 ,那么就需要将打表的范围扩大到要求的范围之外,然后再选取需要的元素。
贪心策略就是一种积累,既然贪心,就要追求高效
var biao:array[0..600000] of longint; s,numb:ansistring; n,i,last,k,m,j,a,b,l,w,t:longint; max:char; function min(a,b:longint):longint; begin if a<b then exit(a); exit(b); end; begin assign(input,'number.in');reset(input); assign(output,'number.out');rewrite(output); readln(k,m); i:=1; j:=1; biao[1]:=1; for l:=2 to k do begin a:=2*biao[i]+1; b:=4*biao[j]+5; if a<b then begin biao[l]:=a; inc(i); end else if a=b then begin biao[l]:=a; inc(i); inc(j); end else begin biao[l]:=b; inc(j); end; end; numb:=''; for i:=1 to k do begin str(biao[i],numb); s:=s+numb; end; n:=length(s); writeln(s); if n=m then begin writeln(''); close(input); close(output); halt; end; if m=0 then begin writeln(s); close(input); close(output); halt; end; // t:=0; w:=0; for t:=1 to n-m do begin max:='0'; for i:=w+1 to min(m+t,n) do if s[i]>max then begin max:=s[i]; w:=i; end; write(max); end; close(input); close(output); end.
2(durle)
题目大意
对任意给定的m(m∈N+)和n(n∈N+),满足m<n,构造一初始集合:P={x|m≤x≤n,x∈N+}(m,n≤100)。现定义一种d规则如下:若存在a∈P,且存在K∈N+ ,K>1,使得K´a∈P,则修改P为:P=P-{y|y=s´a,s∈N+ } ,并称该d规则具有分值a。现要求编制一个程序,对输入的m,n值,构造相应的初始集合P,对P每应用一次d规则就累加其相应的分值,求能得到最大累加分值的d规则序列,输出每次使用d规则时的分值和集合p的变化过程。
输入格式:
输入仅一行,M,N的值。
输出格式:
输出每次使用d规则时的分值和集合p的变化过程(即变化后的集合内所有的数,每个数用空格隔开),注意D后面有个空格,冒号后面有个空格。如果没有一次可以变化就输出0。
样例输入:
(1)
1 10
(2)
56 57
样例输出:
(1)
5 : 1 2 3 4 6 7 8 9
4 : 1 2 3 6 7 9
2 : 1 3 7 9
3 : 1 7
1 :
(2)
0
用到的数据结构,算法
模拟,贪心
正确分析
正确分析题目要求和样例,我们知道,对于给定的一个区间里的数,如果存在一个数是另外几个数的约数,我们就继续进行操作。那么如过一个数拥有的倍数的个数和另一个数相同,那么我们选择较大的那个元素。如果倍数的个数不同,那么我们选择倍数个数较少的元素。
错误原因
没有选择正确的贪心策略,没有正确的理解题意
反思
仔细分析题意根据题目的信息,来推导算法,有的时候,找不到合适的算法就按照题目的要求模拟就可以。
program liukee; var a:array[0..100] of longint; f:array[0..100] of longint; m,n,i,sum,min,j,k:longint; flag:boolean; begin assign(input,'drule.in'); reset(input); assign(output,'drule.out'); rewrite(output); readln(m,n); if n=m+1 then begin writeln(0); close(input); close(output); halt; end; for i:=m to n do f[i]:=true; flag:=false; sum:=n-m+1; while sum>0 do begin fillchar(a,sizeof(a),0); min:=maxlongint; for i:=m to n do if f[i] then for j:=m to n do if f[j] then if (i<>j)and(j mod i=0) then inc(a[i]); for i:=n downto m do if (a[i]<>0)and(a[i]<min)then begin min:=a[i]; k:=i; end; if min=maxlongint then break; flag:=true; write(k,' : '); for i:=m to n do if (i mod k=0)and(f[i]) then begin f[i]:=false; dec(sum); end; for i:=m to n do if f[i] then write(i,' '); writeln; end; if flag=false then writeln(0); close(input); close(output); end.