Noip2014普及组

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.


你可能感兴趣的:(Noip2014普及组)