Orz教主第五次模拟(做题情况+题目分析+代码)[未完]

Orz教主第五次模拟

题目一览:

一、最大匹配:https://www.vijos.org/p/1662

二、旅行:       https://www.vijos.org/p/1661

三、资源勘探:https://www.vijos.org/p/1663

四、排列统计:https://www.vijos.org/p/1660


一、最大匹配

①题目大意:

       从A数组与B数组中各自取出k个数并一一配对,使得配对的元素差的绝对值之和最大

②做题情况:

       考虑不清楚是一个很严重的问题——没有去验证方法的正确性就直接开打,从而导致致命错误的出现;没有进行对拍也是一个很失败的地方——如果当时对过拍,恐怕错误就会暴露出来。。。。。。最水的题都做不对还谈何拿到高分!?——[当时此题分数为30分]

③题目分析:

       AB数组排序后,答案每次加上当前max(abs(maxA-minB),abs(maxB-minA))(应该都知道匹配过的不能再选吧),最后输出即可

④代码:

type
        arr=array[0..100001] of int64;
var
        n,k,i,l1,l2,r1,r2:longint;
        ans,q,p:int64;
        a,b:arr;
function max(a,b:int64):int64;
begin
        if a>b then exit(a);
        exit(b);
end;
procedure qsort(var x:arr; l,r:longint);
var
        i,j:longint;
        m:int64;
begin
        i:=l; j:=r;
        m:=x[random(j-i+1)+i];
        while i<=j do begin
                while x[i]<m do inc(i);
                while x[j]>m do dec(j);
                if i<=j then begin
                        x[0]:=x[i];
                        x[i]:=x[j];
                        x[j]:=x[0];
                        inc(i); dec(j);
                end;
        end;
        if i<r then qsort(x,i,r);
        if l<j then qsort(x,l,j);
end;
begin
        randomize;
        readln(n,k);
        for i:=1 to n do read(a[i]);
        for i:=1 to n do read(b[i]);
        readln;
        qsort(a,1,n);
        qsort(b,1,n);
        l1:=1; r1:=n;
        l2:=1; r2:=n;
        for i:=1 to k do begin
                q:=abs(a[r1]-b[l1]);
                p:=abs(b[r2]-a[l2]);
                if q>p then begin
                        inc(l1);
                        dec(r1);
                        inc(ans,q);
                end else begin
                        inc(l2);
                        dec(r2);
                        inc(ans,p);
                end;
        end;
        writeln(ans);
end.


二、旅行

①题目大意:

       给出一个数组,做出一些调整后使得相邻两元素差的绝对值总和最小;调整的规则:可以交换相邻两元素的位置,但每次交换的位置必 须在前一次交换的位置之后[比如每次交换了A[j]和A[j+1],那么下次交换A[k]和A[k+1]必须满足j<k]

②做题情况:

       思维不能很好的转弯——看出是dp之后就开始想转移方程,但没想过从后往前推会比从前往后推要简单很多。没去从另一个方面去思考真的很糟糕——[当时此题分数为20分]

③题目分析:

       从后往前推会比较容易——假设当前位置为i,则只需考虑以下2种情况:

       1.a[i]没往后移

       2.a[i]往后移

       f[i,0]表示i没后移后的最小体力消耗,f[i,1]表示i后移i~n的最小体力消耗,sum[i]表示1~i相邻元素差的绝对值的和,则有以    下几个转移方程:

       1.f[i,0]:=min(f[i+1,0]+abs(a[i]-a[i+1]){i+1没后移},f[i+1,1]+abs(a[i]-a[i+2]){i+1后移后,原位置就被i+2所取代});

       2.f[i,1]:=min(f[i,1],sum[j]-sum[i+1]+abs(a[i]-a[j])+min(f[j+1,0]+abs(a[i]-a[j+1]),f[j+1,1]+abs(a[i]-a[j+2])));{j=n-1~1}

       {sum[j]-sum[i+1]代表i后移到j后i~j-1相邻元素差的绝对值的总和,f[j+1,0]+abs(a[i]-a[j+1]);,f[j+1,1]+abs(a[i]-a[j+2])[这两个分离出来后就会很容易理解,因此不加多解释]}

       3.f[i,1]:=min(f[i,1],sum[n]-sum[i+1]+abs(a[i]-a[n]));{i后移到n时的特殊判断}

       方程中有一些情况本来应该要分离出来判断,但其中的操作(把a[n+1]赋为a[n])可以使得其少做些判断。最后的答案应为min(f[1,0],f[1,1])

④代码:

var
        f:array[0..2001,0..1] of longint;
        a,sum:array[0..2001] of longint;
        n,i,j:longint;
function min(a,b:longint):longint;
begin
        if a<b then exit(a);
        exit(b);
end;
begin
        readln(n);
        for i:=1 to n do read(a[i]);
        readln;
        for i:=2 to n do sum[i]:=sum[i-1]+abs(a[i]-a[i-1]);
        fillchar(f,sizeof(f),$7f shr 1);
        f[n,0]:=0; f[n,1]:=0;
	a[n+1]:=a[n];
        for i:=n-1 downto 1 do begin
                f[i,0]:=min(f[i+1,0]+abs(a[i]-a[i+1]),f[i+1,1]+abs(a[i]-a[i+2]));
                for j:=i+1 to n-1 do
                f[i,1]:=min(f[i,1],sum[j]-sum[i+1]+abs(a[i]-a[j])+min(f[j+1,0]+abs(a[i]-a[j+1]),f[j+1,1]+abs(a[i]-a[j+2])));
                f[i,1]:=min(f[i,1],sum[n]-sum[i+1]+abs(a[i]-a[n]));
        end;
        writeln(min(f[1,0],f[1,1]));
end.

三、资源勘探

①题目大意:

       给出一个n×m的矩阵,对于左上角坐标为(1,1)、右下角坐标为(x,y)[x=1~n,y=1~m]的子矩阵,如果在这个子矩阵中恰好只有一个a[i,j(i=1~x,j=1~y)这个值,总答案加一

②做题情况:

       心态调整不好会很影响发挥——第二题的打击让我难以静下心来思考第三题——这是十分不好的,如果能调整好心态,以平常心对待题目,分数也就不会在20分止步![当时此题分数为20分]

③题目分析:

       f[i,0]表示i这个值在横坐标中最先出现的地方,f[i,1]表示i这个值在横坐标中第二出现的地方,它们的初始值都为m+1,然后从前往后(也就是i=1~n→j=1~m)计算答案。具体流程用图片说明会更加容易明白

       注:圆圈为i这个值所在的位置,绿色部分为增加答案的部分,灰色部分为减去答案的部分

                  初始值都为m+1                                                   最小的横坐标出现使得答案增加(尽管有的不一定合法)


                  第二小的横坐标出现并减去不合法部分               更新第二小的横坐标并继续减去不合法部分


                 更新最小的横坐标,增加答案的同时                    更新第二小的横坐标并再次减去不合法部分

                 减去不合法部分

       简单的说,就是假设合法的f[i,0]~f[i,1]-1和这段格子以下的矩形部分都是答案,然后在遇到矛盾部分(出现的i的横坐标比f[i,0]或f[i,1]小)后再减去不合法的部分,最后所得就为答案

④代码:

const
        mo=19900907;
var
        f:array[0..1210001,0..1] of int64;
        n,m,i,j,a,k:longint;
        ans:int64;
begin
        readln(n,m);
        for i:=1 to n*m do begin
                f[i,0]:=m+1;
                f[i,1]:=m+1;
        end;
        for i:=1 to n do begin
                for j:=1 to m do begin
                        read(a);
                        k:=n-i+1;
                        if j<=f[a,0] then begin
                                ans:=ans+(f[a,0]-j)*k;
                                ans:=ans-(f[a,1]-f[a,0])*k;
                                ans:=(ans+mo) mod mo;
                                f[a,1]:=f[a,0];
                                f[a,0]:=j;
                        end else if j<=f[a,1] then begin
                                ans:=ans-(f[a,1]-j)*k;
                                ans:=(ans+mo) mod mo;
                                f[a,1]:=j;
                        end;
                end;
                readln;
        end;
        writeln(ans);
end.


四、排列统计(尚未AC,之后再完善)

①题目大意:

②做题情况:

③题目分析:

④代码:


五、总结:

       这一套题并不算难(毕竟是前几年的题),但在这一次测试中暴露出来的问题还是十分严重的!虽说隔了一段时间没有在限定时间内做题并评测,但这出错率还是太过惊人了……一定要在这一次测试中吸取教训,在不同的题上出现的问题要及时改掉,以防在真正的比赛结束之后懊悔地说:“啊!我做错了!”

       剩下的时间已不算多了,接下来要更加努力才行啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值