您的位置:首页 > 其它

magic(NOIP2016普及组复赛)

2016-11-26 09:40 337 查看
第四题:(magic)

方案一:

暴力,四重循环,枚举每一个数字的在每个位置出现的个数,然后再加起来即可

理想分数:35~45分

方案二:

我们可以用一个数轴来表示出四个数的位置:

     A      B            C     D

__|____|_________|___|____

        2i         6i+k         i

从题意中我们可以得出xB~xA=2(xC~xD)

(xC~xB)÷3>xB~xA  那么 xC~xB>3(xB~xA) 然后xC~xB=3(xB~xA)+k{k为任意值} 最后 xC~xB=6(xC~xD)+k

设xC~xD=i 那么 xA~xB=2i,xB~xC=6i+k;

那么就需要枚举i 和 xC的位置和xB 的位置,因为k是拿不准的。

加答案时就只用乘另外3个数在输入时出现的个数。

Inc(a[j,1],w[i1]*w[k]*w[l]);

这样就可以很快的算出所有方案的个数。

理想分数:80~85分

方案三:

那么我们只能想想100分方法了。

根据上面的方法,我们可以想到一个绝妙的n方的方法。

首先枚举i,这个免不了,然后算出前缀和和后缀和。

还是刚刚那个图:

    A       B            C     D

__|____|_________|___|____

        2i        6i+k       i

我们算出后缀和就是到达C最小的取值范围8i+1.

Sj 表示到j这个位置最多有多少个C和D可以存放的位置。

S[j]=S[j+1]+w[j]*w[k];

J是枚举C的位置的,k是由C算出的D的位置,w[i]就是表示i这个数在输入时出现的次数。

这样就可以有效的枚举出C和D在后面出现的个数。

在枚举A的位置,算出B的位置,再像上次一样加答案:

Inc(a[j,1],S[k+6i+1]*w[k]);

K就是由j算出来的B的位置,k+6i+1就是当前C最小的位置,再乘一个B的个数。这样就相当于85分方法的三个数相乘。

算前缀和同理,用来算C和D的方案数。

代码:

var
a:array[1..15000,1..4]of longint;
b,w:array[0..40000]of longint;
n,m,i,j,k,l,i1:longint;
s,s1:array[0..15001]of longint;
bz:boolean;
begin
assign(input,'magic.in');reset(input);
assign(output,'magic.out');rewrite(output);
readln(n,m);
for i:=1 to m do
begin
readln(b[i]);
inc(w[b[i]]);
end;
for i:=1 to n div 9 do
begin
fillchar(s,sizeof(s),0);
fillchar(s1,sizeof(s1),0);
for j:=n-i downto 8*i+1 do
s[j]:=s[j+1]+w[j]*w[j+i];
for j:=1 to n-8*i do
begin
i1:=j+i*2;
if (w[i1]>0)and(w[j]>0) then
begin
inc(a[j,1],s[j+8*i+1]*w[i1]);
inc(a[i1,2],s[j+8*i+1]*w[j]);
end;
end;
for j:=2*i to n-7*i-1 do
s1[j]:=s1[j-1]+w[j]*w[j-2*i];
for j:=8*i+1 to n-i do
begin
i1:=j+i;
if (w[i1]>0)and(w[j]>0) then
begin
inc(a[i1,4],s1[j-6*i-1]*w[j]);
inc(a[j,3],s1[j-6*i-1]*w[i1]);
end;
end;
end;
for i:=1 to m do
writeln(a[b[i],1],' ',a[b[i],2],' ',a[b[i],3],' ',a[b[i],4]);
close(input);
close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: