T2:
题目描述
在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果。例如,对某一观点表示支持的有 1498 人,反对的有 902 人,那么赞同与反对的比例可以简单的记为
1498:902。
不过,如果把调查结果就以这种方式呈现出来,大多数人肯定不会满意。因为这个比例的数值太大,难以一眼看出它们的关系。对于上面这个例子,如果把比例记为 5:3,虽然与真实结果有一定的误差,但依然能够较为准确地反映调查结果,同时也显得比较直观。
现给出支持人数 A,反对人数 B,以及一个上限 L,请你将 A 比 B 化简为 A’比 B’,要求在 A’和 B’均不大于 L 且 A’和 B’互质(两个整数的最大公约数是 1)的前ᨀ下, A’/B’ ≥ A/B且 A’/B’ - A/B 的值尽可能小。
输入
输入文件名为 ratio.in。
输入共一行,包含三个整数 A, B, L,每两个整数之间用一个空格隔开,分别表示支持人数、反对人数以及上限。
输出
输出文件名为 ratio.out。
输出共一行,包含两个整数 A’, B’,中间用一个空格隔开,表示化简后的比例。
样例输入
1498 902 10
样例输出
5 3
数据范围限制
【数据说明】
对于 100%的数据, 1 ≤ A ≤ 1,000,000, 1 ≤ B ≤ 1,000,000, 1 ≤ L ≤ 100,A/B ≤ L。
这道题就是一道大大的水题,当然我竟然一次没做对,就是因为没看清楚a'/b'一定要大于a/b,就这样我第一次只水了80分,所以下次做题一定要细心,把题目的每个要求及条件都在草稿纸上一一列出来方便检查和调试。
代码:
var r,min:real; a,b,l,i,j,x,y:longint; function gcd(x,y:longint):longint; var z:longint; begin while x mod y<>0 do begin z:=x mod y; x:=y; y:=z; end; exit(y); end; begin assign(input,'ratio.in'); reset(input); assign(output,'ratio.out'); rewrite(output); readln(a,b,l); r:=a/b; min:=maxLongint; for i:=1 to l do for j:=1 to l do if (gcd(i,j)=1) and (i/j>=r) and (i/j-r<min) then begin min:=i/j-r; x:=i; y:=j; end; writeln(x,' ',y); close(input); close(output); end.
T3:
题目大意:这道题的题目意思是说在一个n*n的螺旋矩形中,求出第i行第j个是什么数。
样例输入:
4 2 3
样例输出:
14
表示4*4的一个螺旋矩阵的第2,3个数是14.
这道题关键是要想到把一个螺旋矩阵分“层”,也就是把矩阵变成一个“回”字,一层一层的分开,然后想到这点之后还有一点就是如何判断i,j点在哪一层?
其实我们只要多找几个数,多摸索一下规律,我们就发现其实判断i,j点在哪一层,只用求出min(i,j,n-i+1,n-j+1)的值就行了,这个最小值一定是当前i,j点所在的层。然后当我们知道第i,j在哪一层之后,接下来就非常好办了,先把外围的层去掉,然后可以选择模拟,也可以用公式,总之根本不难实现,代码:
ar n,i,j,st,k,l:longint; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; begin assign(input,'matrix.in'); reset(input); assign(output,'matrix.out'); rewrite(output); readln(n,i,j); k:=min((min(min(i,j),n-i+1)),n-j+1); i:=i-k+1; j:=j-k+1; st:=4*n*(k-1)-4-4*k*(k-2); inc(st); dec(n,(k-1)*2); if i=1 then inc(st,j-1) else if j=n then inc(st,n+i-2) else if i=n then inc(st,n*3-j-2) else inc(st,n*4-3-i); writeln(st); close(input); close(output); end.
T4:
题目大意:指在一个n*m的矩阵中选一个r*c的矩阵,当然这矩阵r行不一定相邻,c列也不一定相邻,但是选了第i行就必须选完,选第j列也必须选完。
例如:
5 5 2 3 9 3 3 3 9 9 4 8 7 4 1 7 4 6 6 6 8 5 6 9 7 4 5 6 1然后选完的矩阵的每个相邻之数的差的和就是这个矩阵的分值,现在要求你求一个最小分值。
该矩阵中分值最小的 2 行 3 列的子矩阵由原矩阵的第 4 行、第 5 行与第 1 列、第 3 列、第 4 列交叉位置的元素组成,为
答案=6
这道题目的难点在于,双重Dfs会超时,优化又太难加,而多维Dp根本也不会做,所以我们可以考虑降维的方法,也就是先dfs再dp,这样就能大大减少编程复杂度!
我们dfs选完行之后,就可以拿列来dp了,当然反之亦然。我们如何dp呢?我们可以想到阶段划分的是以每一列来划分,但是单单这一个条件不够,因为题目中还有一个条件就是只能选c列,也就是还要的一个阶段就是当前到了第i列选了多少列?所以我们可以设f[i,j]表示前i列选j列的最小分值。这里需注意的一点是:前i列当中第i列是必须得选的,所以,这个状态也可以表示成在必选第i列的情况下,再在前i-1列选j列的最小分值。
然后我们想一想决策,f[i,j]肯定是有f[..,j-1]加上第i列得来的,而这个空缺的空就是我们的决策,这里可以表示前k列选j-1列,然后再选第i列当做第J列。我们可以得到如下的一个状态转移方程:
f[i,j]:=min{f[k,j-1]+sum[k,i]+d[i]},sum[i,j]表示第i和第j两列横向分值差,而d[i]表示第i列纵向分值差,加上第i列其实只要加上这两个数即可。
代码:
var n,m,r,c,i,j,k,ans:longint; a,sum,f:array[0..16,1..16] of longint; bz,d:array[0..16] of longint; function min(x,y:longint):longint; begin if (x<y) then exit(x) else exit(y); end; procedure work; begin fillchar(sum,sizeof(sum),0); fillchar(d,sizeof(d),0); for i:=1 to m do for j:=1 to r-1 do inc(d[i],abs(a[bz[j],i]-a[bz[j+1],i])); for i:=1 to m-1 do for j:=i+1 to m do for k:=1 to r do inc(sum[i,j],abs(a[bz[k],i]-a[bz[k],j])); fillchar(f,sizeof(f),5); for i:=1 to m do begin f[i,1]:=d[i]; for j:=2 to min(i,c) do for k:=1 to i-1 do f[i,j]:=min(f[i,j],f[k,j-1]+sum[k,i]+d[i]); ans:=min(ans,f[i,c]); end; end; procedure dg(k,tot:longint); begin if k+(r-tot)>n then exit; if tot>r then begin work; exit; end; bz[tot]:=k; dg(k+1,tot+1); dg(k+1,tot); end; begin assign(input,'submatrix.in'); reset(input); assign(output,'submatrix.out'); rewrite(output); readln(n,m,r,c); for i:=1 to n do for j:=1 to m do read(a[i,j]); ans:=maxlongint; dg(1,1); writeln(ans); close(input); close(output); end.