这次比赛算是比较难吧,但是,我的排名仍然没降~ 90+10+0+30=130分
第一题:
https://61.142.113.109/senior/#main/show/2557
题目描述:
2557. 【NOIP2011模拟9.9】单词分类 (StandardIO)
Oliver为了学号英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类。
两个单词可以分为一类当且仅当组成这两个单词的各个字母的数量均相等。
例如“AABAC”,它和“CBAAA”就可以归为一类,而和“AAABB”就不是一类。
现在Oliver有N个单词,所有单词均由大写字母组成,每个单词的长度不超过100.你要告诉Oliver这些单词会被分成几类。
Input
输入文件的第一行为单词个数N,以下N行每行为一个单词。
Output
输出文件仅包含一个数,表示这N个单词分成的类数。
Sample Input
3
AABAC
CBAAA
AAABB
Sample Output
2
【数据范围】
对于70%的数据满足N<=100。
对于100%的数据满足N<=10000。
考试时水法90分,加个优化就过了~,
其实只要对每个字符串的每一位进行排序,
再对整个字符串组进行排序,最后就看看有多少个不一样的字符串,输出就行了
参考程序:
var n,i,j,l,ans,t:longint;
a:array[1..10000,1..100]of char;
b:array['A'..'Z']of longint;
s:string;
ch:char;
procedure kuaipai(l,r:longint);
var i,j:longint;
mid,t:array[1..100]of char;
begin
i:=l;j:=r;
mid:=a[(l+r)div 2];
repeat
while a[i]<mid do inc(i);
while a[j]>mid do dec(j);
if i<=j then
begin
t:=a[i];
a[i]:=a[j];
a[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if l<j then kuaipai(l,j);
if i<r then kuaipai(i,r)
end;
begin
readln(n);
for i:=1 to n do
begin
readln(s);
fillchar(b,sizeof(b),0);
l:=0;
for j:=1 to length(s) do
begin
a[i,j]:=s[j];
inc(b[a[i,j]]);
end;
for ch:='A' to 'Z' do
begin
while b[ch]>0 do
begin
dec(b[ch]);
inc(l);
a[i,l]:=ch;
end;
end;
end;
kuaipai(1,n);
t:=1;
while true do
begin
i:=t;
inc(ans);
for j:=i+1 to n do
if a[i]<>a[j] then
begin
t:=j;
break;
end;
if t=i then break;
if t=n then
begin
inc(ans);
break;
end;
end;
writeln(ans);
end.
第二题:
https://61.142.113.109/senior/#main/show/2558
题目描述:
2558. 【NOIP2011模拟9.9】过河问题 (StandardIO)
在一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸。而东岸有一条小船。
船太小了,一次只能乘坐两人。每个人都有一个渡河时间T,船划到对岸的时间等于船上渡河时间较长的人所用时间。
现在已知N个人的渡河时间T,Oliver想要你告诉他,他们最少要花费多少时间,才能使所有人都过河。
注意,只有船在东岸(西岸)时东岸(西岸)的人才能坐上船划到对岸。
Input
输入文件第一行为人数N,以下有N行,每行一个数。
第i+1行的数为第i个人的渡河时间。
Output
输出文件仅包含一个数,表示所有人都渡过河的最少渡河时间。
Sample Input
4
6
7
10
15
Sample Output
42
【样例解释】
初始:东岸{1,2,3,4},西岸{}
第一次:东岸{3,4},西岸{1,2} 时间7
第二次:东岸{1,3,4},西岸{2} 时间6
第三次:东岸{1},西岸{2,3,4} 时间15
第四次:东岸{1,2},西岸{3,4} 时间7
第五次:东岸{},西岸{1,2,3,4} 时间7
所以总时间为7+6+15+7+7=42,没有比这个更优的方案。
【数据范围】
对于40%的数据满足N<=8
对于100%的数据满足N<=100000。
一道制杖的递推贪心题,
设f[i]表示1~i个人过河的最短时间,
那么f[i]=min(f[i-1]+a[1]+a[i],f[i-2]+a[1]+a[i]+a[2]*2),
初值f[1]=a[1], f[2]=a[2]
数据很水,输入的渡河时间是呈升序的,不需要排序~
参考程序:
var i,n:longint;
a,f:array[1..100000]of longint;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
begin
readln(n);
for i:=1 to n do read(a[i]);
f[1]:=a[1];
f[2]:=a[2];
for i:=3 to n do
f[i]:=min(f[i-1]+a[1]+a[i],f[i-2]+a[1]+a[i]+a[2]*2);
writeln(f[n]);
end.
第三题:
https://61.142.113.109/senior/#main/show/2559
题目描述:
2559. 【NOIP2011模拟9.9】最短路 (StandardIO)
给定一个包含N个点,M条边的无向图,每条边的边权均为1。
再给定K个三元组(A,B,C),表示从A点走到B点后不能往C点走(即路径中不能出现连续三个点为ABC)。注意三元组是有序的,如可以从B点走到A点再走到C点。
现在你要在K个三元组的限制下,找出1号点到N号点的最短路径,并输出任意一条合法路径,会有Check检查你的输出。
Input
输入文件第一行有三个数N,M,K,意义如题目所述。
接下来M行每行两个数A,B,表示A,B间有一条边。
再下面K行,每行三个数(A,B,C)描述一个三元组。
Output
输出文件共两行数,第一行一个数S表示最短路径长度。
第二行S+1个数,表示从1到N所经过的节点。
Sample Input
4 4 2
1 2
2 3
3 4
1 3
1 2 3
1 3 4
Sample Output
4
1 3 2 3 4
【数据范围】
对于40%的数据满足N<=10,M<=20,K<=5。
对于100%的数据满足N<=3000,M<=20000,K<=100000。
亏我比赛时写了一大堆制杖的代码,加了一些奇奇怪怪的东西维护答案,结果爆0了~
原来是数据有问题,不需要输出第二问,之后就打了暴力宽搜,轻松的水过去了~
参考程序:
var n,m,k,i,j,x,y,t,l,r:longint;
f:array[0..3000,0..3000]of longint;
a:array[0..3000,0..3000] of longint;
data:array[1..100000,1..3]of longint;
begin
readln(n,m,k);
for i:=1 to m do
begin
readln(x,y);
a[x,y]:=1;
a[y,x]:=1;
end;
for i:=1 to k do
begin
readln(x,y,t);
f[x,y]:=t;
end;
l:=0;
r:=1;
data[1,1]:=1;
while l<r do
begin
inc(l);
t:=data[l,1];
for i:=1 to n do
begin
if a[t,i]=0 then continue;
if f[data[l,2],data[l,1]]=i then continue;
inc(r);
if i=n then
begin
writeln(data[l,3]+1);
exit;
end;
data[r,1]:=i;
data[r,2]:=data[l,1];
data[r,3]:=data[l,3]+1;
end;
end;
end.
第四题:
https://61.142.113.109/senior/#main/show/1347
题目描述:
1347. 环中环 (Standard IO)
被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在3秒内解决,可见此题难度之大。
问题是这样的:n个整数围成一个环,老师要求选出其中的若干数,使得选中的数所组成的环中,两个相邻数的差的绝对值不等于1。在满足这个前提下,问最多能取多少个数。
Input
第一行一个正整数n,表示有n个数
第二行n个整数,a1、a2……an 按顺时针方向围成一个环。
Output
一个正整数,即表示最多能选多少个数。
Sample Input
5
1 2 3 5 2
Sample Output
3
【样例解释】
最多能选3个数
既选择(1,3,5)或者(2,5,2)
【数据范围】
30%的数据,n≤10
50%的数据,n≤100
70%的数据,n≤1000
100%的数据,n≤100000,ai≤1100000
用了水法,时间超限80分,设b[i]表示以第i个数为结尾,最多选的个数,c[i]表示以第i个数结尾最多能选的个数的序列开头在哪个位置
参考程序(时间超限80分):
var n,i,j,max:longint;
a,b,c:array[0..100000]of longint;
begin
readln(n);
for i:=1 to n do read(a[i]);
c[1]:=1;
for i:=1 to n do
begin
for j:=i-1 downto 1 do
if abs(a[i]-a[j])<>1 then
begin
if b[i]<b[j]+1 then
begin
b[i]:=b[j]+1;
c[i]:=c[j];
end;
end;
if b[i]=0 then
begin
b[i]:=1;
c[i]:=i;
end;
end;
for i:=1 to n do
begin
if abs(a[c[i]]-a[i])<>1 then
begin
if b[i]>max then max:=b[i];
end;
end;
writeln(max);
end.