2016.07.14【初中部 NOIP提高组 】模拟赛C题解

来源:互联网 发布:java短链接实现 编辑:程序博客网 时间:2024/05/22 01:47

题目:http://blog.csdn.net/fengyingjie2/article/details/51915621

总结:这次比赛的题目,有水有难的。最后两道题都是我们没有学习过的内容,所以用不是正解的算法来说。


T1:

输油管道。这道题看起来十分蒙蔽。考试的时候打了400行还爆0,气死了!!当时我是想枚举每个点,然后广搜的。不过这样时间复杂度很高。于是我换了一种方法。广搜到一个点,发现这个点是'.'的话,枚举管道即可。

<span style="font-size:14px;">type        arr=array[1..4] of longint;var        s:array['+'..'|',1..4] of longint;        ss:array[1..4] of longint=(3,4,1,2);        sum:arr;        abc:array[1..7] of char=('|','-','+','1','2','3','4');        i,j,k,n,m,ax,ay,bx,by,head,tail,xx,yy:longint;        a:array[0..26,0..26] of char;        d:array[1..1500,1..2] of longint;        bz,B:array[0..26,0..26] of boolean;        dx:array[1..4] of longint=(-1,0,1,0);        dy:array[1..4] of longint=(0,1,0,-1);function pd(a,b:arr):boolean;var        i:longint;begin        for i:=1 to 4 do                if a[i]<>b[i] then exit(false);        exit(true);end;begin        fillchar(a,sizeof(a),'.');        s['|',1]:=1; s['|',2]:=0; s['|',3]:=1; s['|',4]:=0;        s['-',1]:=0; s['-',2]:=1; s['-',3]:=0; s['-',4]:=1;        s['+',1]:=1; s['+',2]:=1; s['+',3]:=1; s['+',4]:=1;        s['1',1]:=0; s['1',2]:=1; s['1',3]:=1; s['1',4]:=0;        s['2',1]:=1; s['2',2]:=1; s['2',3]:=0; s['2',4]:=0;        s['3',1]:=1; s['3',2]:=0; s['3',3]:=0; s['3',4]:=1;        s['4',1]:=0; s['4',2]:=0; s['4',3]:=1; s['4',4]:=1;//记录每个点的可通行方向        readln(n,m);        for i:=1 to n do        begin                for j:=1 to m do                begin                        read(a[i,j]);                        if a[i,j]='M' then                        begin                                ax:=i;                                ay:=j;                        end;                        if a[i,j]='Z' then                        begin                                bx:=i;                                by:=j;                        end;                end;                readln;        end;        fillchar(bz,sizeof(bz),true);        tail:=1;        d[1,1]:=ax;        d[1,2]:=ay;        for i:=1 to 4 do        begin                if a[ax+dx[i],ay+dy[i]]<>'.' then s['M',i]:=1;                if a[bx+dx[i],by+dy[i]]<>'.' then s['Z',i]:=1;        end;//记录m,z的可通行方向。        while head<>tail do        begin                inc(head);                for i:=1 to 4 do                        if s[a[d[head,1],d[head,2]],i]=1 then                        begin                                xx:=d[head,1]+dx[i];                                yy:=d[head,2]+dy[i];                                if a[xx,yy]='.' then                                begin                                        for k:=1 to 4 do                                        begin                                                sum[k]:=0;                                                if (a[xx+dx[k],yy+dy[k]]<>'.')and(s[a[xx+dx[k],yy+dy[k]],ss[k]]=1)  then                                                        sum[k]:=1;                                        end;                                        for k:=1 to 7 do                                                if pd(sum,s[abc[k]]) then                                                begin                                                        writeln(xx,' ',yy,' ',abc[k]);                                                        halt;                                                end;                                end;                                if (xx>0)and(yy>0)and(xx<=n)and(yy<=m)and(bz[xx,yy])then                                begin                                        inc(tail);                                        d[tail,1]:=xx;                                        d[tail,2]:=yy;                                        bz[xx,yy]:=false;                                end;                        end;        end;end.//广搜出可搜到的'.',判断一下即可。</span>
T2:

数码问题。比赛的时候因为看起来超时于是没做。丢分啊!!!其实就是记录输入的数的坐标就可以了,否则爆(空)炸(间)。然后判断一下需要移动的次数,然后转换一下与他同一行,同一列的数的坐标,即可。

<span style="font-size:14px;">var        n,k,i,j,ans1,ans2:longint;        a,b,c,x,y:array[0..1000] of longint;begin        readln(n,k);        for i:=1 to k do        begin                readln(a[i],b[i],c[i]);                x[i]:=(a[i]-1) div n+1;                y[i]:=(a[i]-1) mod n+1;//位置公式        end;        for i:=1 to k do        begin                if x[i]<=b[i] then                        ans1:=abs(b[i]-x[i]) else                        ans1:=(n-x[i])+b[i];                if y[i]<=c[i] then                        ans2:=abs(c[i]-y[i]) else                        ans2:=(n-y[i])+c[i];//记录次数,分别为行需要转换几次,列转换几次                writeln(ans1+ans2);//输出一共次数                for j:=i+1 to k do                begin                        if x[i]=x[j] then                                y[j]:=(y[j]+ans2-1) mod n+1;                        if c[i]=y[j] then                                x[j]:=(x[j]+ans1-1) mod n+1;//更新同行,列的数的坐标                end;        end;end.</span>
T3:

这题好像是转2进制然后压位,然而我题目看不懂,讲不了,暴力50分。

T4:

这题就是用线段树,可是不会线段树,用一个类似于线段树的方法,但是速度不快。为O(n²)。就是输入的数,建立一个数组,表示1-n数的端点插入的可以得到的值。记录的时候,记录l+1~r-1,因为端点不可以重合嘛。暴力得了70分。

<span style="font-size:14px;">var        c:array[0..100000] of longint;        bz:array[0..100000] of boolean;        i,j,n,ans,a,b:longint;begin        readln(n);        for i:=1 to n do        begin                readln(a,b);                for j:=a+1 to b-1 do                        inc(c[j]);//记录一下                writeln(c[a]+c[b]);//输出                c[a]:=0;                c[b]:=0;//用过了,赋值为0        end;end.</span>

0 0