dls的比赛真的真的好duliu啊
link
link
这题题面简洁明了,看似清新,实际是一个大力推式子的题,区分了我这种不会推式子的人,首先写一写方差的公式,我们可以把静态序列的方差写成这样
∑ i = 1 n a i 2 n − ( ∑ a i ) 2 n 2 = ∑ a i 2 n − 1 n 2 ∑ i = 1 n ∑ j = 1 n a i a j \frac{\sum_{i=1}^n a_i^2}{n}-\frac{(\sum a_i)^2}{n^2} = \frac{\sum a_i^2}{n}-\frac{1}{n^2}\sum_{i=1}^n \sum_{j=1}^na_ia_j n∑i=1nai2−n2(∑ai)2=n∑ai2−n21i=1∑nj=1∑naiaj
把后面那一项, i = j i=j i=j和 i ≠ j i \ne j i̸=j分开算贡献
∑ i = 1 n a i 2 n − 1 n 2 ∑ i = 1 n a i 2 − ∑ i ∑ j [ i ≠ j ] a i a j \frac{\sum_{i=1}^n a_i^2}{n}-\frac{1}{n^2}\sum_{i=1}^na_i^2-\sum_{i}\sum_j[i \ne j]a_ia_j n∑i=1nai2−n21i=1∑nai2−i∑j∑[i̸=j]aiaj
我们现在考虑算序列的所有子集的方差和,先枚举一个 k k k代表子集大小,那么大小为 k k k的子集的贡献为
( n − 1 k − 1 ) k ∑ i = 1 n a i 2 − ( n − 1 k − 1 ) k 2 ∑ i = 1 n a i 2 − ( n − 2 k − 2 ) k 2 ∑ i ≠ j a i a j \frac{\tbinom{n-1}{k-1}}{k}\sum_{i=1}^na_i^2-\frac{\tbinom{n-1}{k-1}}{k^2}\sum_{i=1}^na_i^2-\frac{\tbinom{n-2}{k-2}}{k^2}\sum_{i \ne j}a_ia_j k(k−1n−1)i=1∑nai2−k2(k−1n−1)i=1∑nai2−k2(k−2n−2)i̸=j∑aiaj
我们有这三项东西,每一项的右边和 a a a有关的我们都能用线段树轻松维护,至于前面的组合数系数,就又是轮到了推式子的时刻
( n − 1 k − 1 ) k \frac{\tbinom{n-1}{k-1}}{k} k(k−1n−1)
这一项是最简单的,我们只用一个配凑组合数的技巧就能搞定,数学竞赛也经常用
( n − 1 k − 1 ) k = 1 k ( n − 1 ) ! ( k − 1 ) ! ( n − k ) ! = 1 n n ! k ! ( n − k ) ! = ( n k ) n \frac{\tbinom{n-1}{k-1}}{k}=\frac{1}{k}\frac{(n-1)!}{(k-1)!(n-k)!}=\frac{1}{n}\frac{n!}{k!(n-k)!}=\frac{\tbinom{n}{k}}{n} k(k−1n−1)=k1(k−1)!(n−k)!(n−1)!=n1k!(n−k)!n!=n(kn)
( n − 1 k − 1 ) k 2 \frac{\tbinom{n-1}{k-1}}{k^2} k2(k−1n−1) 差分。。。
有点晚了,未完待续。。。
link
#include
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
using namespace std;
const int N=300;
int n,A,B,C,T,a[N][N],ans[N][N],tag[N];
int Ans[N][N],t[6]={0,0,1,3,8,20};
inline int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
inline int Get(int x)
{
if (x<2) return Get(n-(2-x)+1);
if (x>n) return Get(x-n+1);
return x;
}
inline void Input()
{
n=read(),A=read(),B=read(),C=read();
T=read();
FOR(i,1,T) FOR(j,1,n) a[i][j]=read();
ans[1][2]=1;ans[1][1]=2;FOR(i,3,n) ans[1][i]=i;
ans[2][1]=1;FOR(i,2,n) ans[2][i]=Get(i+1);
ans[3][1]=1;FOR(i,2,n) ans[3][i]=Get(i+3);
ans[4][1]=1;FOR(i,2,n) ans[4][i]=Get(i+8);
ans[5][1]=1;FOR(i,2,n) ans[5][i]=Get(i+20);
return;
}
inline void Turn(int p,int step)
{
int b[N];
b[1]=a[p][1];
FOR(i,2,n) b[i]=a[p][Get(i+step)];
FOR(i,1,n) a[p][i]=b[i];
For(i,5,2) while (step>=t[i]) step-=t[i],Ans[p][++Ans[p][0]]=i;
return;
}
inline void SWAP(int p)
{
swap(a[p][1],a[p][2]);
Ans[p][++Ans[p][0]]=1;
return;
}
inline void Solve(int p)
{
int pos2,ok;
FOR(i,1,n) tag[i]=0;
tag[2]=1;
if (a[p][1]==2) SWAP(p);
FOR(i,2,n) if (a[p][i]==2) pos2=i;
FOR(i,2,n)
{
int check=i-pos2;
if (check<0) check=n-2-(pos2-i)+1;
if (a[p][i]-2==check) tag[a[p][i]]=1;
}
while (1)
{
FOR(i,2,n) if (a[p][i]==2) pos2=i;
if (a[p][1]!=1)
{
int endpos=Get(pos2+a[p][1]-2);
tag[a[p][1]]=1;
Turn(p,endpos-2);
SWAP(p);
}
else
{
int tmp,ok=1;
FOR(i,2,n)
{
int check=i-pos2;
if (check<0) check=n-2-(pos2-i)+1;
if (a[p][i]-2!=check)
{
tag[a[p][i]]=1;
ok=0;
tmp=i;
}
}
if (!ok)
{
Turn(p,tmp-2);
SWAP(p);
}
else
{
Turn(p,pos2-2);
break;
}
}
}
if (!Ans[p][0]) Ans[p][++Ans[p][0]]=1,Ans[p][++Ans[p][0]]=1;
return;
}
inline void Output()
{
FOR(i,1,5)
{
FOR(j,1,n) printf("%d ",ans[i][j]);
printf("\n");
}
FOR(i,6,A)
{
FOR(j,1,n) printf("%d ",j);
printf("\n");
}
FOR(i,1,T)
{
printf("%d ",Ans[i][0]);
FOR(j,1,Ans[i][0]) printf("%d ",Ans[i][j]);
printf("\n");
}
return;
}
int main()
{
Input();
FOR(i,1,T)
Solve(i);
Output();
return 0;
}