一直在改题,很多题解都没写了~刚好有点空,就短短滴总结一下昨天的比赛吧(ノ=Д=)ノ┻━┻
第一题:
https://61.142.113.109/senior/#main/show/2540
题目描述:
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗?
Input
输入文件的第一行包含两个正整数N,M。M表示总共能够用来采药的时间,N代表山洞里的草药的数目。接下来的N行每行包括两个的整数,分别表示采摘某株草药的时间Ti和这株草药的价值Vi。
Output
输出文件仅包含一个整数表示规定时间内可以采到的草药的最大总价值。
Sample Input
3 9 10 10 8 1 1 2
Sample Output
3
Data Constraint
50%的数据中 N,M ≤ 1000; 100%的数据中 N,M ≤ 100000,Ti,Vi ≤10。
一道01背包问题,但是.................
50%的数据中 N,M ≤ 1000; 100%的数据中 N,M ≤ 100000,Ti,Vi ≤10。
所以,我们可以优化一下多重背包.
我们可以先用一个二位数组记录每种情况的个数,之后再把每一种背包都拆分成若干份,使得这若干份小背包通过组合,可以组合出1~背包数中的每一种可能(这一段要理解好)
假设一种背包的数量为X
则X可以拆分成2^0+2^1+……+2^log(x)
如果拆分完X还有剩余,则最后一项的值是剩下的数,
之后把这些数进行01背包,就可以算出最后的答案。
好吧这题我还没改出来,就附上个50分的01背包代码吧~
参考代码:
请勿抄袭!请勿抄袭!请勿抄袭!重要的事情说三遍!
var i,j,t,n:longint;
f:array[0..3000,0..3000]of longint;
w,v:array[1..3000]of longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
begin
read(t,n);
for i:=1 to t do
read(w[i],v[i]);
for i:=1 to t do
for j:=1 to n do
if j>=w[i] then
f[i,j]:=max(f[i-1,j],f[i-1,j-w[i]]+v[i]) else
f[i,j]:=f[i-1,j];
writeln(f[t,n]);
end.
第二题:
https://61.142.113.109/senior/#main/show/2541
题目描述:
给定一个N*M的矩阵,记录左上角为(1,1),右下角为(N,M),现在从(1,1)开始取数,每次只能向下或向右移动一个单位,最终到达(N,M),我们把路径上所有的数相乘,记为C。使C的结果最大已经不能满足我们了,现在我们想让C末尾的零最少。
Ps.11000末尾有3个零,100000100末尾有2个零。
Input
输入文件matrix.in的第一行包含两个正整数N,M表示矩阵大小。
接下来N行每行M个正整数给出整个矩阵。
Output
输出文件名为matrix.out。包含一个整数表示所求最小值。
Sample Input
3 3
1 2 3
10 5 100
10 8 9
Sample Output
1
Data Constraint
Hint
【数据规模和约定】
30%的数据满足 N , M ≤5;
100%的数据满足 1 < N, M ≤ 1000,所有输入数据不超过32位整范围。
这道题是要求从左上角走到右下角所经过的数字的积末尾的0的数量最小
一开始想到搜索,但是我DFS爆搜只能过到N=16&M=16,之后就机智滴想到了DP,
先把每个数的因数2和因数5的个数统计出来,
设状态F[i,j,1]表示从1,1到i,j尾数最少0的数的因数2的个数,F[i,j,2]表示从1,1到i,j尾数最少0的数的因数5的个数,那么得出状态:
tx1:=f[i-1,j,1]+b[i,j]; tx2:=f[i-1,j,2]+c[i,j];
ty1:=f[i,j-1,1]+b[i,j];ty2:=f[i,j-1,2]+c[i,j];
f[i,j,1]:=min(min(f[i,j,1],tx1),ty1);
f[i,j,2]:=min(min(f[i,j,2],tx2),ty2);
其中,b[i,j]表示输入矩阵[i,j]的因数2的个数;
c[i,j]表示输入矩阵[i,j]的因数5的个数;
tx1表示当前F数组[i,j]上面的数的因数2的个数;
tx2表示当前F数组[i,j]上面的数的因数5的个数;
ty1表示当前F数组[i,j]左边的数的因数2的个数;
ty2表示当前F数组[i,j]左边的数的因数5的个数;
之后就可以愉快滴AC了!
参考代码:
请勿抄袭!请勿抄袭!请勿抄袭!重要的事情说三遍!
var n,m,t,tx1,tx2,ty1,ty2:int64;
i,j:longint;
a,b,c:array[0..1001,0..1001]of int64;
f:array[0..1001,0..1001,1..2]of int64;
function min(x,y:int64):int64;
begin
if x<y then exit(x) else exit(y);
end;
begin
readln(n,m);
for i:=1 to n do
for j:=1 to m do
begin
read(a[i,j]);
t:=a[i,j];
while (t mod 2=0) and (t>0) do
begin
t:=t div 2;
b[i,j]:=b[i,j]+1;
end;
t:=a[i,j];
while (t mod 5=0) and (t>0) do
begin
t:=t div 5;
c[i,j]:=c[i,j]+1;
end;
end;
fillchar(f,sizeof(f),$7f);
f[1,1,1]:=b[1,1]; f[1,1,2]:=c[1,1];
for i:=1 to n do
for j:=1 to m do
begin
if (i=1) and (j=1) then continue;
tx1:=f[i-1,j,1]+b[i,j]; tx2:=f[i-1,j,2]+c[i,j];
ty1:=f[i,j-1,1]+b[i,j]; ty2:=f[i,j-1,2]+c[i,j];
f[i,j,1]:=min(min(f[i,j,1],tx1),ty1);
f[i,j,2]:=min(min(f[i,j,2],tx2),ty2);
end;
writeln(min(f[n,m,1],f[n,m,2]));
end.
第三题:
https://61.142.113.109/senior/#main/show/2542
题目描述:
对于排列(P1,P2,...,PN),定义(i,j)为逆序对当且仅当i < j且Pi > Pj。统计{1,2,...,N}的所有排列中,逆序对数量为M的排列数量。
Input
输入文件count.in第一行包含两个正整数N,M。
Output
输出文件count.out应包含一个整数,表示满足条件的排列数除以124567的余数。
Sample Input
3 1
Sample Output
2
Data Constraint
Hint
【数据规模和约定】
30%的数据, N ≤ 10;
100%的数据,0 < N,M ≤ 1000。
非常简单的找规律,递推公式:
f[i,j]:=f[i,j-1]+f[i-1,j]-f[i-1,j-i]
参考代码:
var n,m,i,j:longint;
f:array[0..1000,-1..1000]of longint;
begin
readln(n,m);
for i:=1 to n do f[i,0]:=1;
for i:=2 to n do
for j:=0 to 1000 do
begin
if j<i then f[i,j]:=(f[i-1,j]+f[i,j-1])mod124567
else f[i,j]:=(f[i-1,j]+f[i,j-1]-f[i-1,j-i]+124567)mod124567;
if f[i,j]<0 then f[i,j]:=0;
end;
writeln(f[n,m]);
end.
第四题:
https://61.142.113.109/senior/#main/show/2543
题目描述:
平面上给定N个两两不同的整点,统计以给定的点为顶点,且直角边平行于坐标轴的直角三角形数。
Input
输入文件right.in第一行为一个整数N。
以下N行,每行给出一个点的坐标。
Output
输出文件名为right.out。输出一个整数表示统计结果。
Sample Input
4
0 0
0 1
1 0
1 1
Sample Output
4
Data Constraint
Hint
【数据规模和约定】
30%的数据满足 N ≤ 100;
50%的数据满足 N ≤ 1000;
100%的数据满足0 < N≤ 100000,所有坐标不超过32位整数范围。
如果用普通的O(n³)的方法,只有30分,而O(n²)也只能50分,所以要AC要再进一步优化
我们可以直接枚举两个点,然后枚举两个点,所在的列上顶点的个数-2则为这两个点所能贡献的答案.
但是由于坐标很大~所以,我们需要把列坐标的个数压一下位,压成一堆类似叫做连成的数具体如何进行请自行思考或看参考代码
压了列坐标之后,则可把行坐标排个序,然后直接枚举两个行相等的点,如果行不相等则可直接break
参考代码:
var n,i,j,k:longint;
s:int64;
a:array[0..100000,1..2]of longint;
b,c,w,num:array[0..100000]of longint;
procedure kuaipai(l,r:longint);
var i,j,mid,t:longint;
begin
i:=l;j:=r;
mid:=a[(l+r)div 2,2];
repeat
while a[i,2]<mid do inc(i);
while a[j,2]>mid do dec(j);
if i<=j then
begin
t:=a[i,2];
a[i,2]:=a[j,2];
a[j,2]:=t;
t:=w[i];
w[i]:=w[j];
w[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;
procedure kuaipai2(l,r:longint);
var i,j,mid,t:longint;
begin
i:=l;j:=r;
mid:=a[(l+r)div 2,1];
repeat
while a[i,1]<mid do inc(i);
while a[j,1]>mid do dec(j);
if i<=j then
begin
t:=a[i,1];
a[i,1]:=a[j,1];
a[j,1]:=t;
t:=num[i];
num[i]:=num[j];
num[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if l<j then kuaipai2(l,j);
if i<r then kuaipai2(i,r);
end;
begin
readln(n);
for i:=1 to n do
begin
readln(a[i,1],a[i,2]);
w[i]:=i;
end;
kuaipai(1,n);
a[0,2]:=a[1,2];
k:=1;
for i:=1 to n do
begin
if a[i,2]<>a[i-1,2] theninc(k);
b[i]:=k;
inc(c[k]);
end;
for i:=1 to n do
num[w[i]]:=b[i];
kuaipai2(1,n);
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i,1]=a[j,1] then
s:=s+(c[num[i]]-1)+(c[num[j]]-1) else break;
writeln(s);
end.