jzoj C组 2017.1.15比赛
第一题
题目描述
小x有一个由n个整数组成的数列。他现在可以任意交换数列中两个相邻的元素。小x想知道,能否通过一些操作,使得任意两个相邻的元素不同。
输入
第一行一个整数t,表示测试数据的组数。
每组数据第一行包含一个整数n,表示数列中元素的个数。第二行包含n个整数a1,a2,…,an,表示数列中元素的初始状态。
输出
输出t行,对于第i组测试数据,如果小x能够得到他所想要的序列,输出“YES”,否则输出“NO”(不包含引号)。
样例输入
3
1
1
3
1 1 2
4
7 7 7 7
样例输出
YES
YES
NO
数据范围限制
【数据范围】
对于100%的数据:1<=t<=100,1<=n<=100,1<=ai<=1000。
找到每种元素的个数,如果这个元素的个数大于(n+1) div 2就输出NO,否则输出YES
代码如下:
var bool:boolean;
t,i,j,n,k,max,min:longint;
a:array[1..1000]of longint;
begin
assign(input,'permutation.in');
assign(output,'permutation.out');
reset(input);
rewrite(output);
readln(t);
for k:=1 to t do
begin
fillchar(a,sizeof(a),#0);
readln(n);
min:=1001;
for i:=1 to n do
begin
read(j);
inc(a[j]);
if j>max then max:=j;
if j<min then min:=j;
end;
bool:=false;
for i:=min to max do
begin
if a[i]>(n+1)div 2 then
begin
bool:=true;
break;
end;
end;
if bool then writeln('NO')
else writeln('YES');
end;
close(input);
close(output);
end.
第二题
题目描述
输入
第一行两个用空格分开的整数n和m,分别表示P(x)和Q(x)的最高项指数。
第二行包含n+1用空格分开的整数,a0,a1,…,an,表示P(x)的每项系数。
第三行包含m+1用空格分开的整数,b0,b1,…,bm,表示Q(x)的每项系数。
输出
如果最后得到的极限为正无穷,输出“Infinity”;
如果为负无穷,输出“-Infinity”;
如果最后得到的极限为0,输出“0/1”;
否则,输出一个最简分数,为所得极限的值,以“p/q”的形式,p为分子,q为分母。
样例输入
limit.in1:
2 1
1 1 1
2 5
limit.in2:
1 0
-1 3
2
limit.in3:
0 1
1
1 0
limit.in4:
2 2
2 1 6
4 5 -7
limit.in5:
1 1
9 0
-5 2
样例输出
limit.out1:
Infinity
limit.out2:
-Infinity
limit.out3:
0/1
limit.out4:
1/2
limit.out5:
-9/5
数据范围限制
对于100%的数据:0<=n,m<=100,|ai|,|bi|<10^5。
看数据可以发现,数值是由两行的第一个数决定的。
如果一正一负则输出-号
如果n>m则输出Infinity
如果n=m则将a[1]和b[1]约分后输出,要记得输出符号
如果n小于m则输出0/1
代码如下:
var n,m,x,y:longint;
bool1,bool2:boolean;
procedure yue;
var i:longint;
begin
for i:=2 to x do
if (x mod i=0)and(y mod i=0) then
begin
x:=x div i;
y:=y div i;
end;
end;
begin
assign(input,'limit.in');
assign(output,'limit.out');
reset(input);
rewrite(output);
readln(n,m);
readln(x);
readln(y);
if x<0 then bool1:=true else bool1:=false;
if y<0 then bool2:=true else bool2:=false;
x:=abs(x); y:=abs(y);
if n>m then
begin
if (bool1=true)and(bool2=false)or(bool1=false)and(bool2=true) then write('-');
write('Infinity');
end
else
if n=m then
begin
yue;
if (bool1=true)and(bool2=false)or(bool1=false)and(bool2=true) then write('-');
write(x,'/',y);
end
else write(0,'/',1);
close(input);
close(output);
end.
第三题
题目描述
小x有两个长度均为n的字符串s和w。小x认为s和w是不可比较的,当存在i和j (0<=i,j<=n),si>wi并且sj< wj。si表示字符串s中的第i个元素,相似的,wj表示字符串w中第j个元素。
字符串模板由数字和问号“?”构成,“?”并不会成对出现。
小x现在有两个长度为n的字符串模板。每个问号可以填不同的数或相同的数,小x想要计算填数的方案数,使得这两个字符串不可比较。最终得到的字符串可以包含前导零。
帮助小x计算出方案数除以1000000007的余数。
输入
第一行一个整数n,表示字符串模板的长度。
第二、第三行,每行包含一个长度为n的字符串模板。
输出
一行一个整数,方案数除以1000000007的余数。
样例输入
strings.in1:
2
90
09
strings.in2:
2
11
55
strings.in3:
5
?????
?????
样例输出
strings.out1:
1
strings.out2:
0
strings.out3:
993531194
数据范围限制
对于20%的数据 :1<=n<=5
对于50%的数据: 1<=n<=25
对于100%的数据: 1<=n<=10^5
这题是分五种情况去判断
①如果st1[i]和st2[i]都是’?’则a[i,1]:=a[i-1,1]*55(即0~9,1~9……9)
a[i,2]同上
总方案数ans*100
②如果st1[i]=’?’和st2[i]<>’?’a[i,1]:=a[i-1,1]*(10-st2[i] (数值))
a[i,2]:=a[i,2-1]*(st2[i] (数值)+1) ans:=ans *10
③如果st1[i]<>’?’和st2[i]=’?’,其原理如上
④如果st1[i]<>’?’和st2[i]<>’?’ 而且st1[i]>st2[i]则将a[i,1]:=a[i-1,1]
⑤如果st1[i]<>’?’和st2[i]<>’?’ 而且st1[i]
const mod1=1000000007;
var n,i,x,ans,l,y:longint;
st1,st2:ansistring;
f:array[0..100000,1..2]of longint;
begin
assign(input,'strings.in');
assign(output,'strings.out');
reset(input);
rewrite(output);
readln(n);
f[0,1]:=1; f[0,2]:=1;
readln(st1);
readln(st2);
ans:=1;
y:=1;
l:=0;
for i:=1 to n do
if (st1[i]=st2[i])and(st1[i]='?') then
begin
f[i,1]:=(int64(f[i-1,1])*55) mod mod1;
f[i,2]:=(int64(f[i-1,2])*55) mod mod1;
ans:=(int64(ans)*10*10) mod mod1;
inc(l);
end
else
if (st1[i]='?') then
begin
val(st2[i],x);
f[i,1]:=(int64(f[i-1,1])*(10-x)) mod mod1;
f[i,2]:=(int64(f[i-1,2])*(x+1)) mod mod1;
ans:=(int64(ans)*10) mod mod1;
end
else
if st2[i]='?' then
begin
val(st1[i],x);
f[i,1]:=(int64(f[i-1,1])*(x+1)) mod mod1;
f[i,2]:=(int64(f[i-1,2])*(10-x)) mod mod1;
ans:=(int64(ans)*10) mod mod1;
end
else
if st1[i]>st2[i] then f[i,1]:=f[i-1,1] else f[i,2]:=f[i-1,2];
ans:=ans-f[n,1]-f[n,2];
if (f[n,1]>0)and(f[n,2]>0) then
begin
for i:=1 to l do y:=(int64(y)*10) mod mod1;
ans:=ans+y;
end;
if ans<0 then ans:=ans+mod1;
write(ans);
close(input);
close(output);
end.
第四题
题目描述
小x有一个由n个顶点构成的加权有向图,这张图中,任意两个顶点之间的都有两条方向不同的边。小x很喜欢玩图,现在他发明了一个新的游戏:
这个游戏共有n步。
在第i步时,小x把第xi个点从图中删除,同时删除所有与xi相连的边,包括xi的入边和出边。
每步操作进行前,小x想知道所有剩余顶点之间的最短路径的长度之和,最短路径可以通过任何剩余的顶点。换句话说,我们定义d(i,v,u)是在删除顶点xi之前,顶点v到顶点u的最短路径。
输入
第一行包含一个整数n,表示图的顶点数。
接下来n行,每行n个整数,第i行第j个元素aij表示顶点i到顶点j的边的权值。
最后一行,包含n个不同的整数:x1,x2,…,xn(1<=xi<=n),表示小x删的顶点。
输出
一行用1个空格分开的n个整数,第i个数表示在第i步前所求的值。行末没有多余的空格。
样例输入
shortest.in1:
1
0
1
shortest.in2:
2
0 5
4 0
1 2
shortest.in3:
4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
样例输出
shortest.out1:
0
shortest.out2:
9 0
shortest.out3:
17 23 404 0
数据范围限制
对于30%的数据:1<=n<=50
对于70%的数据:1<=n<=100
对于100%的数据:1<=n<=500,1<=xi<=n,1<=aij<=10^5,aii=0
这题如果直接弗洛伊德可能数值会有很多重复
所以
我们从最后删掉的点一直往会搜到没有删点
每次增加一个点,再判断这个点加进来有没有比原来的最短路径还短的路径,更新数值。直到没有删点。
代码如下:
var n,i,j,k:longint;
a:array[0..505,0..505]of longint;
b,ans:array[0..1010]of longint;
begin
assign(input,'shortest.in');
assign(output,'shortest.out');
reset(input);
rewrite(output);
readln(n);
for i:=1 to n do
begin
for j:=1 to n do read(a[i,j]);
readln;
end;
for i:=1 to n do read(b[i]);
for k:=n downto 1 do
begin
for i:=1 to n do
for j:=1 to n do
begin
if a[b[i],b[k]]+a[b[k],b[j]]<a[b[i],b[j]] then a[b[i],b[j]]:=a[b[i],b[k]]+a[b[k],b[j]];
if (i>=k)and(j>=k) then ans[k]:=ans[k]+a[b[i],b[j]];
end;
end;
for i:=1 to n do write(ans[i],' ');
close(input);
close(output);
end.