俄罗斯方块 tetris
【题意】
俄罗斯方块游戏,在一个宽度为n高度为h的矩阵中进行,给定初始状态,每次给定一个形状的方块,将它放到最靠左进行最少旋转次数可不出现“洞”(就是说同一列方块之间有缝隙)且加入后最高高度不超过h的位置,并输出这个位置,跟一般的俄罗斯方块一样,一行满了便会消行
各种编号对应的方块
0
**
*
*
1
**
*
*
2
**
**
3
**
**
4
***
*
5
**
**
6
****
【输入】
第一行n、m、h(皆小于等于100000)
接下来m行每行一个数字表示加入的方块的形状
【输出】
对于每次加入输出其位置
十分麻烦的题
首先需要一个函数(这里是could)来判断某位置是否能放入一个某形状的方块
然后用线段树来维护,维护两个值,区间内高度最低值和用一个7位2进制数表示的以区间内的点为起点每种形状是否能放入
那么对于每次插入,查询最靠左的点,并更新有关的最多七个点,总查询并更新复杂度为mlogn
对于消行,每次重建线段树即可,消行次数最多为4*m/n,每次重建为nlogn,所以总重建复杂度为mlogn
虽然常数比较大,但这个复杂度对于时限3s的本题还是很轻松的
program tetris;
const
plus:array [0..6,1..4,0..3] of longint
=(
((3,1,0,0),(1,1,2,0),(1,3,0,0),(2,1,1,0)),
((1,3,0,0),(1,1,2,0),(3,1,0,0),(2,1,1,0)),
((1,2,1,0),(2,2,0,0),(0,0,0,0),(0,0,0,0)),
((1,2,1,0),(2,2,0,0),(0,0,0,0),(0,0,0,0)),
((1,2,1,0),(1,3,0,0),(1,2,1,0),(3,1,0,0)),
((2,2,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0)),
((1,1,1,1),(4,0,0,0),(0,0,0,0),(0,0,0,0))
);
dif:array [0..6] of longint=(4,4,2,2,4,1,2);
long:array [0..6,1..4] of longint
=(
(2, 3, 2, 3 ),
(2, 3, 2, 3 ),
(3, 2, 0, 0 ),
(3, 2, 0, 0 ),
(3, 2, 3, 2 ),
(2, 0, 0, 0 ),
(4, 1, 0, 0 )
);
need:array [0..6,1..4,0..2] of longint
=(
((-2,9,9), (0,1,9), (0,9,9), (0,0,9) ),
((2,9,9), (0,0,9), (0,9,9), (-1,0,9) ),
((0,-1,9), (1,9,9), (9,9,9), (9,9,9) ),
((1,0,9), (-1,9,9), (9,9,9), (9,9,9) ),
((1,-1,9), (1,9,9), (0,0,9), (-1,9,9) ),
((0,9,9), (9,9,9), (9,9,9), (9,9,9) ),
((0,0,0), (9,9,9), (9,9,9), (9,9,9) )
);
var
minn,tot,h,n,m,i,j,k,t:longint;
high:array [0..100001] of longint;
min,left,right,status:array [0..200001] of longint;
function could (now,form:longint):longint;
var
ok:boolean;
i,j,k:longint;
begin
for i:=1 to dif[form] do
begin
if (high[now]+plus[form,i,0]>h)or(now+long[form,i]-1>n) then continue;
ok:=true;
for j:=0 to long[form,i]-2 do
if (high[now+j]-high[now+j+1]<>need[form,i,j])
or(high[now+j+1]+plus[form,i,j+1]>h)
then
begin
ok:=false;
break
end;
if ok then exit(i);
end;
exit(0);
end;
procedure change (who,l,r,now:longint);
var
i:longint;
begin
if l=r then
begin
min[now]:=high[who];
status[now]:=0;
for i:=0 to 6 do
if could(who,i)<>0 then status[now]:=status[now] or (1 shl i);
exit;
end;
if who<=(l+r) div 2 then change(who,l,(l+r) div 2,left[now])
else change(who,(l+r) div 2+1,r,right[now]);
status[now]:=status[left[now]] or status[right[now]];
if min[left[now]]<min[right[now]] then min[now]:=min[left[now]]
else min[now]:=min[right[now]];
end;
procedure quick (s,e,now:longint);
var
i,mid:longint;
begin
if s=e then
begin
left[now]:=0;
right[now]:=0;
status[now]:=0;
min[now]:=high[s];
for i:=0 to 6 do
if could(s,i)<>0 then status[now]:=status[now] or (1 shl i);
exit;
end;
mid:=(s+e) div 2;
inc(tot);
left[now]:=tot;
inc(tot);
right[now]:=tot;
quick(s,mid,left[now]);
quick(mid+1,e,right[now]);
status[now]:=status[left[now]] or status[right[now]];
if min[left[now]]<min[right[now]] then min[now]:=min[left[now]]
else min[now]:=min[right[now]];
end;
procedure build ;
begin
tot:=0;
quick(1,n,0);
end;
function find (form,l,r,now:longint):longint;inline;
begin
if l=r then exit(l);
if status[left[now]] or (1 shl form)=status[left[now]] then
exit(find(form,l,(l+r) div 2,left[now]))
else
exit(find(form,(l+r) div 2+1,r,right[now]));
end;
procedure update (now,form,status:longint);
var
i,k:longint;
begin
for i:=0 to long[form,status]-1 do
high[now+i]:=high[now+i]+plus[form,status,i];
for i:=0 to long[form,status]-1 do
change(now+i,1,n,0);
for i:=1 to 3 do
if now-i>0 then
change(now-i,1,n,0);
if min[0]<>0 then
begin
for i:=1 to n do
high[i]:=high[i]-min[0];
build;
end;
end;
begin
assign(input,'tetris.in');
reset(input);
assign(output,'tetris.out');
rewrite(output);
read(n,m,h);
minn:=maxlongint;
for i:=1 to n do
begin
read(high[i]);
if high[i]<minn then minn:=high[i];
end;
for i:=1 to n do
high[i]:=high[i]-minn;
build;
for i:=1 to m do
begin
read(t);
j:=find(t,1,n,0);
writeln(j-1);
k:=could(j,t);
update(j,t,k);
end;
close(input);
close(output);
end.