1.神奇的幻方
题目描述 Description
幻方是一种很神奇的N∗N矩阵:它由数字 1,2,3, … … ,N∗N构成,且每行、每列及两条对角线上的数字之和都相同。
当N为奇数时,我们可以通过以下方法构建一个幻方:
首先将 1写在第一行的中间。之后,按如下方式从小到大依次填写每个数(K= 2,3, … ,N∗N ):
1.若 (K−1)在第一行但不在最后一列,则将 填在最后一行,(K−1)所在列的右一列;
2.若 (K−1)在最后一列但不在第一行,则将填在第一列,( K−1)所在行的上一行;
3.若 ( K−1)在第一行最后一列,则将填在(K −1)的正下方;
4.若 (K−1)既不在第一行,也不在最后一列,如果( K−1)的右上方还未填数,
则将 K填在( K−1)的右上方,否则将填在( K− 1)的正下方。
现给定N,请按上述方法构造N∗N的幻方
输入描述 Input Description
输入文件只有一行,包含一个整数,即幻方的大小。
输出描述 Output Description
输出文件包含N行,每行N个整数,即按上述方法构造出的N∗N的幻方。相邻两个整数之间用单个空格隔开。
样例输入 Sample Input
3
样例输出 Sample Output
8 1 6
3 5 7
4 9 2
数据范围及提示 Data Size & Hint
对于 100%的数据,1 ≤ N ≤ 39且为奇数。
分析:
对于此类暴力题,秒杀100!奋斗
var
n,x,y,ans,i,j:longint;
a:array[1..41,1..41]of integer;
begin
read(n);
x:=1;y:=n div 2+1;a[x,y]:=1;
ans:=2;
while ans<=n*n do
begin
if (ans-1) mod n=0 then inc(x)
else begin dec(x);inc(y); end;
if x=0 then x:=n;
if y>n then y:=1;
a[x,y]:=ans;
inc(ans);
end;
for i:=1 to n do
begin
for j:=1 to n do
write(a[i,j],' ');
writeln;
end;
end.
2.信息传递
题目描述 Description
有个同学(编号为 1 到)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为的同学的信息传递对象是编号为的同学。游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入描述 Input Description
输入共 2行。
第 1行包含1个正整数n,表示n个人
第 2 行包含n 个用空格隔开的正整数T1 ,T 2 ,……,Tn , 其中第i个整数Ti表示编号为i
的同学的信息传递对象是编号为 T i 的同学,Ti≤n 且 Ti≠i。
数据保证游戏一定会结束。
输出描述 Output Description
输出共 1行,包含 1个整数,表示游戏一共可以进行多少轮。
样例输入 Sample Input
5
2 4 2 3 1
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
【输入输出样例 说明】
游戏的流程如图所示。当进行完第 3 轮游戏后,4 号玩家会听到 2 号玩家告诉他自己的生日,所以答案为 3。当然,第 3 轮游戏后,2 号玩家、3 号玩家都能从自己的消息来源得知自己的生日,同样符合游戏结束的条件。
对于 30%的数据, n ≤ 200;
对于 60%的数据, n ≤ 2500;
对于 100%的数据, n≤ 200000。
分析:
其实对于100%数据,只能O(N)或O(N logN)
N点N边,要么是个大环,要么是若干环加单独点,所以可以用上拓扑,
把那些不在环上的点删去,再把剩下的换一个一个数出来,记住每个点只能
向外延一条边
var
a,sum:array[1..200000]of longint;
p:array[1..200000]of boolean;
n,i,j,x,ans,min:longint;
begin
read(n);
for i:=1 to n do begin sum[i]:=0;p[i]:=true; end;
for i:=1 to n do
begin
read(a[i]);
inc(sum[a[i]]);
end;
for i:=1 to n do
if sum[i]=0 then
begin
p[i]:=false;x:=i;
while (p[a[x]]) and (sum[a[x]]=1) do
begin
dec(sum[a[x]]);
p[a[x]]:=false;
x:=a[x];
end;
end;
min:=maxlongint;
for i:=1 to n do
if p[i] then
begin
ans:=1;
p[i]:=false;x:=i;
while p[a[x]] do
begin
p[a[x]]:=false;
inc(ans);
x:=a[x];
end;
if (ans<min)and(a[x]=i) then min:=ans;
end;
writeln(min);
end.
牛牛最近迷上了一种叫斗地主的扑克游戏。 斗地主是一种使用黑桃、红心、梅花、方片的 A 到 K 加上大小王的共 54 张牌来进行的扑克牌游戏。在斗地主中, 牌的大小关系根据牌的数码表示如下:(和斗地主一样)
而花色并不对牌的大小产生影响。 每一局游戏中,一副手牌由 n 张牌组成。游戏者每次可以根据规
定的牌型进行出牌, 首先打光自己的手牌一方取得游戏的胜利。
现在,牛牛只想知道,对于自己的若干组手牌, 分别最少需要多少次出牌可以将它
们打光。 请你帮他解决这个问题。
需要注意的是, 本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。
具体规则如下:
输入文件名为 landlords.in。
第一行包含用空格隔开的 2 个正整数T,n,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据n行, 每行一个非负整数ai,bi,对表示一张牌, 其中ai表
示牌的数码,bi表示牌的花色,中间用空格隔开。 特别的, 我们用1 来表示数码 A, 11 表
示数码 J, 12 表示数码 Q, 13 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示; 小
王的表示方法为 0 1, 大王的表示方法为 0 2。
输入描述 Input Description
输入文件名为 landlords.in。
第一行包含用空格隔开的 2 个正整数T,n,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据n行, 每行一个非负整数ai,bi,对表示一张牌, 其中ai表
示牌的数码,bi表示牌的花色,中间用空格隔开。 特别的, 我们用1 来表示数码 A, 11 表
示数码 J, 12 表示数码 Q, 13 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示; 小
王的表示方法为 0 1, 大王的表示方法为 0 2。
输出描述 Output Description
输出文件名为 landlords.out。
共 T 行,每行一个整数,表示打光第i组手牌的最少次数。
样例输入 Sample Input
输入样例1
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
—————
输入样例2
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2
样例输出 Sample Output
输出样例1
3
—————
输出样例2
6
数据范围及提示 Data Size & Hint
测试点, 我们约定手牌组数 与张数 的规模如下:
测试点编号
分析:
只有顺和点数有关,把可能的顺搜完后(涉及多个点数),
剩下的要么三带一,三带二,四带二(涉及两个点数),
最后单独的怎么打快就怎么打(只涉及一个点数),
反正就那么多牌,暴搜就行了,都不用去想DP,
暴力出奇迹!
var
i,j,n,m,x,y,z,k,t,ans:longint;
a,c:array[0..100000] of longint;
b:array[0..100000] of boolean;
function min(x,y:int64):int64;
begin
if x>y then exit(y) else exit(x);
end;
procedure dfs(now:longint);
var
i,j,x,y,z,z2,k:longint;
begin
if now>=ans then exit;
x:=0; y:=0; z:=0; z2:=0;
for i:=1 to 14 do
begin
if c[i]=1 then inc(x)
else if c[i]=2 then inc(y);
end;
for i:=1 to 14 do
if c[i]=4 then
begin
inc(z2);
if x>=2 then x:=x-2
else if y>=2 then y:=y-2
else if y>=1 then dec(y);
end;
for i:=1 to 14 do
if c[i]=3 then
begin
inc(z);
if x>=1 then dec(x)
else if y>=1 then dec(y);
end;
ans:=min(ans,now+z+z2+x+y);//先处理只打出一个点数的情况
for i:=1 to 8 do//单顺
begin
for j:=i to 12 do
begin
dec(c[j]);
if c[j]<0 then break;
if j-i>=4 then dfs(now+1);
end;
for k:=i to j do inc(c[k]);
end;
for i:=1 to 10 do//二顺
begin
for j:=i to 12 do
begin
dec(c[j],2);
if c[j]<0 then break;
if j-i>=2 then dfs(now+1);
end;
for k:=i to j do inc(c[k],2);
end;
for i:=1 to 11 do//三顺
begin
for j:=i to 12 do
begin
dec(c[j],3);
if c[j]<0 then break;
if j-i>=1 then dfs(now+1);
end;
for k:=i to j do inc(c[k],3);
end;
end;
begin
readln(m,n);
for t:=1 to m do
begin
fillchar(c,sizeof(c),0);
for i:=1 to n do
begin
readln(y,x);
if y=0 then inc(c[14])
else if y=1 then inc(c[12])
else if y=2 then inc(c[13])
else inc(c[y-2]);
end;
ans:=14;
dfs(0);
writeln(ans);
end;
end.