标签:
然而有素质的我选择把题目也粘在上面,喜欢的同学可以做一下
支付宝
(pay.pas/c/cpp)
题目描述
做完前七次Nescafé 模拟赛之后,你已经欠了一大笔电费。现在收电费的已经把你堵在了家里。当然了,你并不是打算一直拖欠电费的人,你只是如果不能用最少的纸币张数凑出电费金额的话会感到十分不爽。本来这是一件很简单的事,但是你平常很少使用标准的纸币,而是习惯去银行领一本支票簿,在每一张上填上自己喜欢的金额然后把这些东西用作纸币付账,这就使问题变得复杂了起来。现在你知道你一共填写了N种金额的支票,第i 种支票的金额和数目分别是Wi 和Ci,而电费的总额是K。为了尽快把收电费的打发走,你需要写一个程序,帮助你确定使用支票数目最少的支付方案。
输入格式
第一行是一个整数N,表示支票金额的种类数。
第二行是 N 个整数W1, W2, ..., WN,表示支票的金额。
第三行是 N 个整数C1, C2, ..., CN,表示支票的数目。
第四行是一个整数 K,表示电费的金额。
输出格式
第一行输出一个整数 T,表示至少需要使用的支票数目。
第二行按顺序输出 N 个整数U1, U2, ..., UN。其中Ui 表示使用第i 种支票的数目。
如果有多种方案,你只需要输出任意一个。
样例输入
3
2 3 5
2 2 1
10
样例输出
3
1 1 1
数据范围与约定
对于20% 的数据,N≤10,Wi≤500,Ci≤200,K≤2000。
对于 100% 的数据,N≤200,Wi, Ci, K≤20000。
解析:二维背包,记录选择方式,注意要完全装满(不装满收电费的回来找你= =)初值除了f[0]=0以外全部maxlongint;
代码
var i,j,m,t,n,k:longint; p:array[0..202,0..20020] of longint; f,w,c:array[0..20202] of longint; function min(a,b:longint):longint; begin if a<b then exit(a) else exit(b); end; procedure mk(x,y,z:longint); var i:longint; begin for i:=k downto y do if (f[i]>f[i-y]+x) then begin f[i]:=f[i-y]+x; p[z][i]:=p[z][i-y]+x; end; end; begin assign(input,‘pay.in‘); reset(input); assign(output,‘pay.out‘); rewrite(output); readln(n); for i:=1 to n do read(w[i]); for i:=1 to n do read(c[i]); readln(k); fillchar(f,sizeof(f),127); f[0]:=0; for i:=n downto 1 do begin j:=0; while c[i]<>0 do begin t:=min(1<<j,c[i]); mk(t,t*w[i],i); c[i]:=c[i]-t; inc(j); end; end; writeln(f[k]); for i:=1 to n do begin write(p[i][k],‘ ‘); k:=k-p[i][k]*w[i]; end; close(input); close(output); end.
SECHS
(sec.pas/c/cpp)
题目描述
对于给定的正整数N,我们把[1, N]中的整数按照字符串的字典序排序得到N 项数列A(N)。例如,N = 11的时候,A(N) = {1, 10, 11, 2, 3, 4, 5, 6, 7, 8, 9}。二元函数 Q(N, K) 的定义域为N, K∈Z+ 且 N≥K,其值为K 在A(N) 中的位置。例如从上面给出的A(11)中可以看出Q(11, 2) = 4。现在你的任务是,对于给定的正整数 K 和M,求最小的正整数N 满足Q(N, K) = M。
输入格式
仅有一行,包含两个正整数K 和M。
输出格式
输出一个正整数N 表示答案。如果不存在这样的N,输出0。
样例输入 1
12 7
样例输出1
102
样例输入 2
100000001 1000000000
样例输出2
100000000888888879
数据范围与约定
对于30% 的数据,满足M, K≤100。
对于 100% 的数据,满足1≤M, K≤109。
解析:先判0,除去之后按位数做
代码(巨短)
var i,j,m,n,k:int64; begin assign(input,‘sec.in‘); reset(input); assign(output,‘sec.out‘); rewrite(output); readln(m,k); n:=1; while n*10<=m do n:=n*10; i:=n; j:=m; while i<>0 do begin k:=k-(j-i+1); i:=i div 10; j:=j div 10; end; if (k<0) or (k>0) and (n=m) then begin writeln(0); close(input); close(output); halt; end else if k=0 then writeln(m) else begin while true do begin n:=n*10; m:=m*10; if k>m-n then k:=k-(m-n) else begin writeln(n+k-1); break; end; end; end; close(input); close(output); end.
数列操作
(sequence.pas/c/cpp)
题目描述
给定一个长度为??的整数数列??=(??1,??2,…,????),并且可以对这个数列进行一种操作:选择两个正整数??,??(1≤??≤??≤??),将????,????+1,…,????同时加上一或者同时减去一。
再给定一个长度为??的整数数列??=(??1,??2,…,????),要求用最少的操作次数将数列??变成数列??。
输入格式
输入文件名为sequence.in,共三行。
第一行包含一个正整数??。
第二行包含??个整数,表示数列??。
第三行包含??个整数,表示数列??。
输出格式
输出文件名为sequence.out,共一行,包含一个正整数,表示最少需要的操作次数。
样例输入
3
3 4 5
6 7 8
样例输出
3
数据范围与约定
对于40%的数据满足,??≤100,0≤|????|,|????|≤100;
对于80%的数据满足,??≤1,000;
对于100%的数据满足,??≤100,000,0≤|????|,|????|≤1,000,000。
这题题干有点问题,显示不出来。大概就是给出当前序列和目标序列,每次将一个区间的所有值加1或减1,输出最少改动次数(详见noip2013火柴排队)
题解:贪心,先分出每一个单独的,正负相同的区间,对每个区间贪心,比前一个低就跳过,比前一个高就加上差值,易证其正确性
代码
var a,b,f,d:array[0..156321] of longint; ans,k,l,m,n,p:int64; i,j:longint; o1,o2:boolean; begin assign(input,‘sequence.in‘); reset(input); assign(output,‘sequence.out‘); rewrite(output); readln(n); for i:=1 to n do read(a[i]); for i:=1 to n do read(b[i]); for i:=1 to n do f[i]:=a[i]-b[i]; for i:=1 to n do begin if ((f[i]>0) and (f[i+1]<=0)) or ((f[i]<0) and (f[i+1]>=0)) then begin inc(l); d[l]:=i; end; end; d[l+1]:=n; for i:=0 to l do begin m:=0; for j:=d[i]+1 to d[i+1] do begin if m<abs(f[j]) then inc(p,abs(f[j])-m); m:=abs(f[j]); end; end; writeln(p); close(input); close(output); end.
喜欢就收藏一下吧,vic个人qq:1064864324。加我来一起讨论竞赛题目,交流感想,共同进步
标签:
原文地址:http://www.cnblogs.com/victorslave/p/4811584.html