整体分析
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.