【srm603】Sum Of Arrays(sum)
(File IO): input:sum.in output:sum.out
Time Limits: 4000 ms Memory Limits: 262144 KB
Description
英雄有两个整数数列A 和B。每个数列有恰好n 个元素。
英雄将会对两个数列进行两次操作:首先,他会将两个数列中的元素按照某种方式重新排列。(他可以将数列排成任意他想要的顺序,包括原本的顺序。交换数列A 和B 的元素是不被允许的,每个数列要独自重排。)在此之后,他会计算出一个有n 个元素的新数列C,按照对于所有i,C[i] = A[i] + B[i]。
英雄喜欢相同的多个数字。他的目标是让C 里面产生尽可能多的相同数字。更正式地说,对于一个给定的C,他对满足下述条件的整数X 和Y 感兴趣:值等于Y 的元素在C 中出现了X 次,并且X 需尽可能的大。
你会获得整数n 以及用于产生数列A 和B 的随机种子。每一组随机种子有六个整数,用a0, a1,… ,a5 以及b0, b1,…,b5表示。算出数列A 和B 之后,你的任务是计算可能的最佳整数对(X,Y )。也就是说,X 必须尽可能地大,并且,如果有多个这样的整数对,那么Y 也必须尽可能地大。
数列A 按照如下定义生成:
•A[0] = a0
•A[1] = a1
•对于在2 到n-1之间的i,有A[i] = (A[i-1]* a2 + A[i-2]*a3 + a4)mod a5
同理,数列B 由类似的定义生成。
Input
多组数据,读入到文件结束。
对于每组数据,第一行为一个整数n——两个等长数列的长度,第二行为六个整数——A 的随机种子a0; a1; a2; a3; a4; a5,第三行为六个整数——B 的随机种子b0; b1; b2; b3; b4; b5。
Output
对于每组数据,输出单独一行,两个整数X 和Y ——符合题目描述的最佳整数对。
Sample Input
3
1 1 1 1 1 2
1 1 1 1 1 2
3
1 1 1 1 1 4
1 1 1 1 1 4
3
1 2 0 0 1 5
0 1 0 0 1 5
14
5 6 2 4 6 11
6 5 2 4 2 7
100000
6274 99908 61138 86540 56297 100000
28275 25494 65423 61118 64925 100000
Sample Output
3 2
2 4
3 2
9 7
3027 102148
【样例说明】
第一组数据:数列为{1,1,1} 和{1,1,1},怎样排列都会得到数列{2,2,2}。所以答案是出现3次2.
第二组数据:数列为{1,1,3}和{1,1,3},如果不重排的话和数列将会是{2,2,6}出现了两次2. 但是如果我们将第一个数列排列成{1,3,1},那么和数列将会是{2,4,4},同样是出现两次的数字,但是在这种情况里第二个值4 更优。
第三组数据:数列为{1,2,1} 和{0,1,1}。重排数列之后是可以得到和数列{2,2,2}的。所以答案是整数对(3,2)。
Data Constraint
对于20% 的数据,n <=10,000。
对于另外20% 的数据,a5, b5 <=10,000。
对于另外60% 的数据,数据组数等于一。
3<= n <=100, 000, 2 <=a5, b5 <=100, 000。
0 <=a0, a1, a2, a3, a4 < a5。
0<= b0, b1, b2, b3, b4 < b5。
解题思路
设a中i出现的次数为
a[i]
a
[
i
]
b中j出现的次数为
b[j]
b
[
j
]
易推知和为i的次数
c[i]=∑i,jmin(a[i],b[j])
c
[
i
]
=
∑
i
,
j
m
i
n
(
a
[
i
]
,
b
[
j
]
)
取最小值不好算,但可以转化为
∑i,j∑k[a[i]>=k][b[i]>=k]
∑
i
,
j
∑
k
[
a
[
i
]
>=
k
]
[
b
[
i
]
>=
k
]
由于独特的数据生成方式,当
k=5
k
=
5
时满足条件的
a[i],b[i]
a
[
i
]
,
b
[
i
]
都不多,暴力算不会超时
当知道
k>5
k
>
5
时的贡献,考虑枚举
k∈[1,4]
k
∈
[
1
,
4
]
,设方程
A(x)=∑i[a[i]>=k]xi,B(x)=∑j[b[j]>=k]xj
A
(
x
)
=
∑
i
[
a
[
i
]
>=
k
]
x
i
,
B
(
x
)
=
∑
j
[
b
[
j
]
>=
k
]
x
j
FFT多项式相乘得出
C(x)
C
(
x
)
统计答案即可。
注意调用次数有些多,与处理一下 Wk2n W 2 n k 和FFT中变换的排序
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 300000
#define db double
#define ll long long
#define L 5
using namespace std;
int l,n,a0,a1,a2,a3,a4,a5,X,Y,ans[N],tota[N],totb[N],A[N],B[N],pos[N];
struct z{
db a,b;
z(db _a=0,db _b=0){a=_a,b=_b;}
}a[N],b[N],c[N],y[N],w[19][N];
z operator+(z a,z b){return z(a.a+b.a,a.b+b.b);}
z operator-(z a,z b){return z(a.a-b.a,a.b-b.b);}
z operator*(z a,z b){return z(a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a);}
void dft(z *a,db sig){
for(int i=0;i<n;i++)y[i]=a[pos[i]];
for(int hf=1,m=2,l=0;m<=n;hf=m,m<<=1,++l)
for(int i=0;i<hf;i++){
z wni=z(w[l][i].a,sig*w[l][i].b);
for(int j=i;j<n;j+=m){
int k=j+hf;
z u=y[j],v=wni*y[k];
y[j]=u+v;y[k]=u-v;
}
}
for(int i=0;i<n;i++)a[i]=y[i];
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
for(int i=0;i<19;i++){
n=1<<i;
w[i][0]=z(1,0);z wn=z(cos(M_PI/(db)n),sin(M_PI/(db)n));
for(int j=1;j<n;j++)w[i][j]=w[i][j-1]*wn;
}
while(~scanf("%d",&l)){
for(int i=0;i<N;i++)tota[i]=totb[i]=ans[i]=0;
scanf("%d %d %d %d %d %d",&a0,&a1,&a2,&a3,&a4,&a5);
int tmp=a5;
++tota[a0];++tota[a1];
for(int i=2;i<l;i++){
int t=(int)(((ll)a1*(ll)a2+(ll)a0*(ll)a3+(ll)a4)%(ll)a5);
++tota[t];a0=a1;a1=t;
}
scanf("%d %d %d %d %d %d",&a0,&a1,&a2,&a3,&a4,&a5);
tmp+=a5;
for(n=1;n<tmp;n=n*2);
for(int i=0;i<n;i++)pos[i]=i;
for(int i=0,p=0;i<n;i++){
if(i<p)swap(pos[i],pos[p]);
for(int j=n>>1;(p^=j)<j;j>>=1);
}
++totb[a0];++totb[a1];
for(int i=2;i<l;i++){
int t=(int)(((ll)a1*(ll)a2+(ll)a0*(ll)a3+(ll)a4)%(ll)a5);
++totb[t];a0=a1;a1=t;
}
int ca,cb;ca=cb=0;
for(int i=0;i<n;i++){
if(tota[i]>=L)A[++ca]=i;
if(totb[i]>=L)B[++cb]=i;
}
for(int i=1;i<=ca;i++)for(int j=1;j<=cb;j++)ans[A[i]+B[j]]+=min(tota[A[i]],totb[B[j]])-L+1;
X=-1;
for(int k=1;k<L;k++){
for(int i=0;i<n;i++){
a[i]=z(tota[i]>=k,0);
b[i]=z(totb[i]>=k,0);
}
dft(a,1);dft(b,1);for(int i=0;i<n;i++)c[i]=a[i]*b[i];dft(c,-1);
for(int i=0;i<n;i++){
int t=(int)round(c[i].a/(db)n);ans[i]+=t;
}
}
for(int i=0;i<n;i++)if(ans[i]>=X)X=ans[i],Y=i;
printf("%d %d\n",X,Y);
}
fclose(stdin);fclose(stdout);
return 0;
}