问题A: 集合删数
【问题描述】
一个集合有如下元素:1是集合元素;若P是集合的元素,则2 * P + 1 , 4 * P + 5也是集合的元素,取出此集合中最小的K个元素,按从小到大的顺序组合成一个多位数,现要求从中删除M个数位上的数字,使得剩下的数字最大,编程输出删除前和删除后的多位数字。
注:不存在所有数被删除的情况
【输入格式】
输入的仅一行,K,M的值,K,M均小于等于30000。
【输出格式】
输出为两行,第一行为删除前的数字,第二行为删除后的数字。
【样例输入】
5 4
【样例输出】
137915
95
删数问题加强版。由于是添加元素,所以队列长度是变化的。有的人可能想到既然队列确定,那么根据题意列出队列,排序后打出表来不就好了?其实不是的。
当数很大时,2*P +1,4*P+5会相差很多。这个区间中会有很多在数列中的数。如果将它们全部入队,总数将很庞大,还会出现丢项。
我们用两个指针分别记录2*a +1,4*b+5的a和b,每次选小的入队,这样在保证单调性的前提下也不会丢项。
参考代码:
program number; var s,ans:ansistring; st:string; c:char; i,j,k,n,m:longint; a,b:longint; p:array[1..60000]of longint; po,len:longint; function min(x,y:longint):longint; begin if x>y then exit(y) else exit(x); end; begin readln(n,m); p[1]:=1; j:=1;i:=1; for k:=2 to n do //入队 begin a:=p[i]*2+1; b:=p[j]*4+5; if a>b then begin inc(j); p[k]:=b; end else if a=b then begin inc(i); inc(j); p[k]:=a; end else begin inc(i); p[k]:=a; end; end; s:=''; for i:=1 to n do begin str(p[i],st); s:=s+st; end; n:=length(s); po:=0; len:=0; ans:=''; while len<n-m do //删数 begin inc(len); c:='0'; for i:=po+1 to min(m+len,n) do if s[i]>c then begin c:=s[i]; po:=i; end; ans:=ans+c; end; writeln(s); writeln(ans); end.
问题B: d-规则问题
【问题描述】
对任意给定的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
贪心。策略:找到m到(m+n)div 2中所有数倍数的个数。每次删除个数最少的最大值,直到无可删为止。
参考代码:
program drule; var n,m:longint; a:array[1..100]of longint; v:array[1..100]of boolean; i,j,mid,min,k:longint; f:boolean; begin readln(n,m); mid:=(n+m)div 2; for i:=n to mid do for j:=i+1 to m do if j mod i=0 then inc(a[i]); fillchar(v,sizeof(v),false); f:=false; while true do begin j:=0; min:=100000000; for i:=mid downto n do if(a[i]>0)and(not v[i])then if a[i]<min then begin min:=a[i]; j:=i; end; if j=0 then break; f:=true; for i:=j to m do if not v[i] then if i mod j=0 then begin v[i]:=true; for k:=1 to i-1 do if i mod k=0 then dec(a[k]); end; v[j]:=true; write(j,' : '); for i:=n to m do if not v[i] then write(i,' '); writeln; end; if not f then writeln('0'); end.
问题C: 极值问题
传送门:http://www.cnblogs.com/saltless/archive/2010/11/10/1873234.html
问题D: 所罗门王的藏宝图
【问题描述】
亨利男爵,约翰上校和勇敢的猎象人夸特曼又一次在绝代佳人弗拉塔的帮助下破解了所罗门王藏宝洞的按钮密码,紧闭的藏宝洞门缓缓打开.三位寻宝英雄迫不及待地冲进藏宝洞.他们完全被展现在眼前的无数奇珍异宝惊呆了.在他们还没有回过神的时候藏宝洞门又自动关闭了,藏宝洞内变得一片漆黑.藉着宝石发出的荧光他们隐约看到紧闭的洞门边有一串若隐若现的数字.面对突如其来的变故约翰上校和夸特曼的脸上露出了惊恐的神色,而亨利男爵却是气定神闲胸有成竹的样子.原来亨利男爵在开始寻宝前就熟读寻宝秘籍,早已掌握了所罗门王藏宝洞的出门密码的奥秘.根据洞门边显现的数字,用寻宝秘籍上记录的神秘方式输入与其相应的密码就可以再次打开洞门.如何获取与洞门边显现的数字对应的密码 ? 这还得从数百年前流行的一个移棋游戏说起.
棋盘上有若干方格排成一行,每个方格中可放1枚棋子.移棋游戏的规则是任意一枚棋子可以沿水平方向跳过与其相邻的棋子进入空着的方格并吃掉被跳过的棋子.其他方式的棋子移动都不是合法移动.对于棋盘上若干棋子的初始布局,如果存在一种合法着法使得最终棋盘上只剩下1枚棋子,则称这种布局为一个完美布局.例如图4中3枚棋子的布局是一个完美布局,移动2步后棋盘上只剩下1枚棋子.用棋盘上最左端棋子开始到最右端棋子结束的方格状态表示棋盘的初始布局,可将图4中的初始布局表示为1101.其中1表示棋子,0表示空格.在棋盘上有3枚棋子的所有布局中,只有1101和1011这2种布局是完美布局,其他的布局都不是完美布局.例如对于棋盘布局111就无法通过合法移动使得棋盘上最终只剩下1枚棋子.
如果藏宝洞门边显现的数字是n,那么与其对应的出门密码就是在棋盘上有n枚棋子时移棋游戏的完美布局数.试设计一个计算出门密码的算法,即计算移棋游戏的完美布局数.
【输入格式】
由文件Treasure.in提供输入数据,文件的第一行中有1个正整数n,表示藏宝洞门边显现的数字,即移 棋游戏的棋盘初始布局中有n枚棋子, 0 < n < 15536 .【输出格式】
将计算出的藏宝洞出门密码,即棋盘上有n枚棋子时移棋游戏的完美布局数输出到文件Treasure.out中.
【样例输入】
3
【样例输出】
2
极其强大的规律! 手推或者搜索找出小数据的解可以发现,数列相邻项的差的相邻项的差(好绕囧 *.*||)是0,4,0,4,…这样的序列!这样就So Easy了~
参考代码:
program treasure; var n,i:integer; sum:longint; begin readln(n); case n of 1,2:writeln('1'); 3:writeln('2'); else begin sum:=3; i:=4; while i<n do begin sum:=sum+3+(i-4) shr 1 shl 2; inc(i); end; writeln(sum); end; end; end.
关于本模拟赛的详细题解请到我的115网盘下载ppt。
地址:http://u.115.com/file/f9b99a780c<贪心与归纳算法.ppt>
本文地址:http://www.cnblogs.com/saltless/archive/2010/11/10/1873239.html
(saltless原创,转载请注明出处)