T2:
传说很遥远的藏宝楼顶层藏着诱人的宝藏。小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。说明书的内容如下:
藏宝楼共有N+1层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。除了顶层外,藏宝楼另有N层,每层M个房间,这M个房间围成一圈并按逆时针方向依次编号为0,…,M-1。其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。每个房间里有一个指示牌,指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间(假定该房间的编号为k),从该房间上楼,上楼后到达上一层的k号房间。比如当前房间的指示牌上写着2,则按逆时针方向开始尝试,找到第2个有楼梯的房间,从该房间上楼。如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。
寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。
请帮助小明算出这个打开宝箱的密钥。
输入输出格式
输入格式:
第一行2个整数N和M,之间用一个空格隔开。N表示除了顶层外藏宝楼共N层楼,M表示除顶层外每层楼有M个房间。
接下来N*M行,每行两个整数,之间用一个空格隔开,每行描述一个房间内的情况,其中第(i-1)*M+j行表示第i层j-1号房间的情况(i=1,2,…, N;j=1,2,…,M)。第一个整数表示该房间是否有楼梯通往上一层(0表示没有,1表示有),第二个整数表示指示牌上的数字。注意,从j号房间的楼梯爬到上一层到达的房间一定也是j号房间。
最后一行,一个整数,表示小明从藏宝楼底层的几号房间进入开始寻宝(注:房间编号从0开始)。
输出格式:
输出只有一行,一个整数,表示打开宝箱的密钥,这个数可能会很大,请输出对20123取模的结果即可。
输入输出样例
输入样例#1:
2 3
1 2
0 3
1 4
0 1
1 5
1 2
1
输出样例#1:
5
【数据范围】
对于50%数据,有0<N≤1000,0<x≤10000;
对于100%数据,有0<N≤10000,0<M≤100,0<x≤1,000,000。
这道题目其实就是一道模拟题,其中如果用纯模拟的方法只能得50分,所以可以优化。
判断到达哪个楼梯房间的时候可以用周期的原理,只求取模后的值来模拟即可——这样就可以大大的减少复杂度了。
代码:
var
bz,num:array[0..10000,0..100] of longint;
c:array[0..10000] of longint;
i,j,n,m,w,ans,sum:longint;
begin
assign(input,'treasure.in'); reset(input);
assign(output,'treasure.out'); rewrite(output);
readln(n,m);
for i:=1 to n do
for j:=1 to m do
begin
readln(bz[i,j],num[i,j]);
if bz[i,j]=1 then inc(c[i]);
end;
readln(w); inc(w);
for i:=1 to n do
begin
ans:=(ans+num[i,w]) mod 20123;
j:=(num[i,w]-1) mod c[i]+1;
sum:=bz[i,w];
while sum<>j do
begin
w:=w mod m+1;
inc(sum,bz[i,w]);
end;
end;
writeln(ans);
close(input);close(output);
end.
当然,其实上面代码的时间复杂度为O(nm),但如果M再大一点的话,即需要O(n)的算法——可以再优化一下,把取模后的值在判断是哪个楼梯的时候可以优化,优化成O(1)的计算,a[i,t]的值就是当前是在哪个楼梯,主要是注意f[i,j]表示的是第i层到第j个房间截止有多少个楼梯房间。f[i,w]+(tot[i,w] mod a[i,0])再取模就是要求的值了。其次还需要注意的是,有可能t的值=0,这时候w就等于第i层最后一个房间——因为等于1的时候是第一个,=0不就是最后一个?
代码(但实质上对于这道题的数据时间并没有体现多少,如果m大一点的话则必须用此方法):
var
n,m,i,j,w,ans,t:longint;
bz:array[1..10000,0..100] of 0..1;
a,tot,f:array[1..10000,0..100] of Longint;
begin
assign(input,'treasure.in'); reset(input);
assign(output,'treasure.out'); rewrite(output);
readln(n,m);
for i:=1 to n do
for j:=1 to m do
begin
readln(bz[i,j],tot[i,j]);
f[i,j]:=f[i,j-1];
if bz[i,j]=1 then
begin
inc(a[i,0]);
a[i,a[i,0]]:=j;
inc(f[i,j]);
end;
end;
readln(W);
inc(w);
for i:=1 to n do
begin
ans:=(ans+tot[i,w]) mod 20123;
if bz[i,w]=1 then dec(tot[i,w]);
t:=((tot[i,w] mod a[i,0])+f[i,w]-1) mod a[i,0]+1;
if t<>0 then w:=a[i,t] else w:=a[i,a[i,0]];
end;
writeln(ans);
close(input); close(output);
end.
T2:
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入输出格式
输入格式:
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出格式:
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。
输入输出样例
输入样例#1:
2 4
3 2
输出样例#1:
2
说明
【数据范围】
对于20%数据,有0<n≤8,0<m≤8,0≤ai≤8;
对于50%数据,有0<n≤20,0<m≤20,0≤ai≤20;
对于100%数据,有0<n≤100,0<m≤100,0≤ai≤100。
这道题目就是赤裸裸的DP,状态也很容易想到——设f[i,j]表示摆i种花在前j个位置上的方案数,显然f[i,j]:=f[i,j]+f[i-1,j-k]。边界f[i,0]:=1;
代码:
var
a:array[1..100] of Longint;
f:array[0..100,0..100] of Longint;
n,m,i,j,k:Longint;
function min(x,y:LONgint):Longint;
begin
if x<y then exit(x) else exit(y);
end;
begin
assign(input,'flower.in'); reset(input);
assign(output,'flower.out'); rewrite(output);
read(n,m);
for i:=1 to n do
read(a[i]);
for i:=0 to n do
f[i,0]:=1;
for i:=1 to n do
for j:=1 to m do
for k:=0 to min(j,a[i]) do
f[i,j]:=(f[i,j]+f[i-1,j-k]) mod 1000007;
writeln(f[n,m]);
close(input); close(output);
end.
T4:
有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家)。不同的国家可能有相同的文化。不同文化的国家对其他文化的看法不同,有些文化会排斥外来文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)。现给定各个国家间的地理关系,各个国家的文化,每种文化对其他文化的看法,以及这位使者游历的起点和终点(在起点和终点也会学习当地的文化),国家间的道路距离,试求从起点到终点最少需走多少路。
输入输出格式
输入格式:
第一行为五个整数 N,K,M,S,T,每两个整数之间用一个空格隔开,依次代表国家
个数(国家编号为 1 到 N),文化种数(文化编号为 1 到 K),道路的条数,以及起点和终点的编号(保证 S 不等于 T);
第二行为 N 个整数,每两个整数之间用一个空格隔开,其中第 i 个数 Ci,表示国家 i的文化为 Ci。
接下来的 K 行,每行 K 个整数,每两个整数之间用一个空格隔开,记第 i 行的第 j 个数为 aij,aij= 1 表示文化 i 排斥外来文化 j(i 等于 j 时表示排斥相同文化的外来人),aij= 0 表示不排斥(注意 i 排斥 j 并不保证 j 一定也排斥 i)。
接下来的 M 行,每行三个整数 u,v,d,每两个整数之间用一个空格隔开,表示国家 u与国家 v 有一条距离为 d 的可双向通行的道路(保证 u 不等于 v,两个国家之间可能有多条道路)。
输出格式:输出只有一行,一个整数,表示使者从起点国家到达终点国家最少需要走的距离数(如果无解则输出-1)。
输入输出样例
输入样例#1:
输入输出样例 1
2 2 1 1 2
1 2
0 1
1 0
1 2 10
输入输出样例 2
2 2 1 1 2
1 2
0 1
0 0
1 2 10
输出样例#1:
输入输出样例 1
-1
输入输出样例 2
10
说明
输入输出样例说明1
由于到国家 2 必须要经过国家 1,而国家 2 的文明却排斥国家 1 的文明,所以不可能到达国家 2。输入输出样例说明2路线为 1 -> 2
【数据范围】
对于 100%的数据,有 2≤N≤100 1≤K≤100 1≤M≤N2 1≤ki≤K 1≤u, v≤N 1≤d≤1000 S≠T 1≤S,T≤N
这道题数据非常的坑,又坑又烂,例如,“正确”的dfs倒过来搜就行了,这里正确为什么要打引号?因为题目中有一个规定就是不能学过重复的文化,还有就是每个文化之间都不能排斥,而不仅仅是两两城市之间不排斥,而这两个规定即使不加同样能AC——因为没有了这个两个规定,即这道题用Floyd也可以做对了!——但是这道题的正解我认为是spfa,因为数据如果大一点,强悍一点,Dfs是过不了的,而floyd答案是错误的,只有spfa才能做对,spfa里面需要很多的判重。
例如——dis[i].bz是判断不能学重复的文化,而dis[i].xuan是选中的文化不能排斥。如果没了这两个判重真不知难点在哪里,然而就算有这两个判重好像这也不是难点吧。
spfa算法的方法:
type
trr=array[0..100] of boolean;
arr=array[0..100] of longint;
var
c:array[1..100] of longint;
a:array[1..100,0..1000] of longint;
bz,d:array[1..100,1..100] of longint;
data:array[1..1000] of longint;
f:array[1..100] of boolean;
dis:array[1..100] of record way:longint; xuan:arr; bz:trr end;
n,k,m,s,t,i,j,x,y,way,head,tail,w:longint;
function pd(x:arr; k:longint):boolean;
var
i:LONGINT;
begin
for i:=1 to x[0] do
if (bz[c[k],c[x[i]]]=1) then exit(false);
exit(true);
end;
begin
assign(input,'culture.in'); reset(input);
assign(output,'culture.out'); rewrite(output);
readln(n,k,m,s,t);
for i:=1 to n do
read(c[i]);
for i:=1 to k do
begin
for j:=1 to k do
read(bz[i,j]);
readln;
end;
fillchar(d,sizeof(d),5);
for i:=1 to m do
begin
read(x,y,way);
inc(a[x,0]);
a[x,a[x,0]]:=y;
if way<d[x,y] then d[x,y]:=way;
inc(a[y,0]);
a[y,a[y,0]]:=x;
if way<d[y,x] then d[y,x]:=way;
end;
head:=0;
tail:=1;
fillchar(dis,sizeof(dis),5);
dis[s].way:=0;
dis[s].xuan[0]:=1;
dis[s].xuan[1]:=s;
data[1]:=s;
while head<tail do
begin
inc(head);
w:=data[head];
for i:=1 to a[w,0] do
if pd(dis[w].xuan,a[w,i]) and (dis[a[w,i]].way>dis[w].way+d[w,a[w,i]]) and dis[w].bz[c[a[w,i]]] then
begin
dis[a[w,i]]:=dis[w];
dis[a[w,i]].way:=dis[a[w,i]].way+d[w,a[w,i]];
dis[a[w,i]].bz:=dis[w].bz;
dis[a[w,i]].bz[c[a[w,i]]]:=false;
inc(dis[a[w,i]].xuan[0]);
dis[a[w,i]].xuan[dis[a[w,i]].xuan[0]]:=a[w,i];
if not f[a[w,i]] then
begin
f[a[w,i]]:=true;
inc(tail);
data[tail]:=a[w,i];
end;
end;
f[w]:=false;
end;
if dis[t].way=84215045 then writeln(-1) else writeln(dis[t].way);
close(input); close(output);
end.