给出一堆括号让你判断其能否匹配,这应该是一道很水的模拟进出栈的题。现在给出模板代码:
var
s:ansistring;
i,j,top,n:longint;
flag:boolean;
a:array[0..1000001]of longint;
function fct(x:char):longint;
begin
case x of
'<':exit(1);
'>':exit(1);
'(':exit(2);
')':exit(2);
'[':exit(3);
']':exit(3);
'{':exit(4);
'}':exit(4);
end;
end;
begin
readln(n);//有n组数据
for j:=1 to n do
begin
a[0]:=5;
flag:=true;
readln(s);//读入的括号序列
top:=0;
for i:=1 to length(s) do
begin
if s[i]='<' then
begin
inc(top);a[top]:=fct('<');
if a[top]>a[top-1] then flag:=false;
end;
if s[i]='(' then
begin
inc(top);a[top]:=fct('(');
if a[top]>a[top-1] then flag:=false;
end;
if s[i]='[' then
begin
inc(top);a[top]:=fct('[');
if a[top]>a[top-1] then flag:=false;
end;
if s[i]='{' then
begin
inc(top);a[top]:=fct('{');
if a[top]>a[top-1] then flag:=false;
end;//都是左括号,进栈
if (s[i]='>')or(s[i]=')')or(s[i]=']')or(s[i]='}') then
if a[top]=fct(s[i]) then dec(top) else flag:=false;//右括号出栈
if top<0 then flag:=false;
if not flag then break;
end;
if top<>0 then flag:=false;
if flag then writeln('YES') else writeln('NO');
end;
end.
在完全理解上面的代码之后,你就可以向下看了。
PS:其实下面的内容和上面并没有什么关系。。。
序列统计
【题目描述】
一个有N个数的数列A(初始时全部为0),并给出M个操作,每个操作给出两个整数l和r,把[l,r]里的数全部加1,最后输出这个序列。
1<=N<=1000000
1<=M<=1000000
【分析】
根据数据范围就可以看出,按照题目的描述去模拟的方法显然会超时。于是我们选用一种叫做差分的技巧(其实还有很多其他的方法,不过这种方法的代码应该最短)求解。如果把此题看成括号匹配,就是说l是左括号,r是右括号,然后打标记——在A[l]上打上+1,在A[r+1]上打上-1。然后一个循环扫描一遍,记录当前经过的标签之和(+1就是加1,-1就是减1)就可以了。
光是语言描述可能不太清楚,下面举个例子:有5个数,操作给出l=2,r=4。
初始:0 0 0 0 0
标记:0 1 0 0 -1
扫描:0 1 1 1 0
看,是不是A[2]~A[4]都变成了1!
这样对于每个操作只要O(1)的时间打标记,最后一重循环统计即可,总时间复杂度O(M+N)。
矩阵统计
【题目描述】
给出一个N*N的矩阵A,初始时全部为0。并给出M个操作,每个操作给出四个整数x1,y1,x2,y2,表示把A[x1,y1]~A[x2,y2]中的所有数都加上1。最后输出整个矩阵。
1<=N<=1000
1<=M<=1000000
【分析】
就是比上一题增加了一个维度,仍然可以用一维的方法来做,不过打标记的方法变了——在A[x1..x2,y1]中打上+1,在A[x1..x2,y2+1]中打上-1,最后的每一行都按照一维方法操作即可。
#include<cstdio>
int f[1010][1010]={0},sum[1010][1010];
int main()
{
int n,m,x1,y1,x2,y2;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for (int j=x1;j<=x2;j++) { f[j][y1]+=1;f[j][y2+1]-=1; }
}
for (int i=1;i<=n;i++) {
int t=0;
for (int j=1;j<=n;j++) {
t+=f[i][j];
sum[i][j]=t;
}
}
for (int i=1;i<=n;i++) {
for (int j=1;j<=n;j++) printf("%d ",sum[i][j]);
printf("\n");
}
return 0;
}
校门外的树
【题目描述】
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
1<=L<=1000000
1<=区域数量<=1000000
【分析】
用数组模拟的方法自然是过不了的,于是我们想到了差分。注意上面的算法都是把某个区间加1,而此题是减1。而且最后输出的不是马路的情况,而是树的数量,所以在最后扫描的时候要略作改动。
var
i,n,m,x,y:longint;
f:array[0..100000001]of shortint;
begin
readln(n,m);
fillchar(f,sizeof(f),0);
for i:=1 to m do begin
readln(x,y);
inc(f[x]);dec(f[y+1]);
end;
x:=0; y:=0;
for i:=0 to n do begin
inc(x,f[i]);
if x=0 then inc(y);
end;
writeln(y);
end.