zr2019暑期高端峯會AB組day8

zr2019暑期高端峯會AB組day8

dls的比賽真的真的好duliu啊

A. 抽象代數題(構造題)

link

  • A=100A=100時,每個序列給它一個唯一的置換
  • A=50A=50時,由於n=50n=50,我們可以構造4949個置換,每個置換讓第一個位置和第ii個位置交換,其他位置不動,那麼交換兩個數需要三次操作,總操作數最多3(n1)3*(n-1)
  • A=30A=30時,我們對前2525個元素構造和11的置換,外加一個前2525位和後2525位交換位置的置換,那麼我們雖然不能直接讓所有元素和位置11交換,但是由於我們分了兩個,它們可以輪流得到和11交換的機會,這樣我們也能得到所有的排列,同樣地,組數分得不一樣也能得到相應的部分分
  • 我們思考AA至少要是幾我們纔可以保證可以得到所有的排列,其實A=2A=2就可以了,我們構造一個位置11和位置22的交換,和一個2n2-n的循環移位,那麼對於每一對需要交換的位置,都可以用循環移位的操作放到1122的位置交換
  • A=5A=5時,我們仿照上面的思路,減少步數的使用,上面的方法慢就慢在循環移位必須移位移位地移動,那麼怎麼樣才能大步大步地移位且能使每一位都能到位置22呢?倍增!但是23=82^3=8還不夠爽快,那麼就用三進制,139271,3,9,27
  • 具體的操作方法:11, 若位置11上的數不是11,把它該在的位置(和22的相對位置)移到11旁邊和它交換,22,若1的位置上時11,找到22後面第一個不應該在那的數,把它放到位置11上重複步驟11

B. 數據結構題(計數題)

link

這題題面簡潔明瞭,看似清新,實際是一個大力推式子的題,區分了我這種不會推式子的人,首先寫一寫方差的公式,我們可以把靜態序列的方差寫成這樣
i=1nai2n(ai)2n2=ai2n1n2i=1nj=1naiaj \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

把後面那一項,i=ji=jiji \ne j分開算貢獻
i=1nai2n1n2i=1nai2ij[ij]aiaj \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

我們現在考慮算序列的所有子集的方差和,先枚舉一個kk代表子集大小,那麼大小爲kk的子集的貢獻爲
(n1k1)ki=1nai2(n1k1)k2i=1nai2(n2k2)k2ijaiaj \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

我們有這三項東西,每一項的右邊和aa有關的我們都能用線段樹輕鬆維護,至於前面的組合數係數,就又是輪到了推式子的時刻

  • (n1k1)k\frac{\tbinom{n-1}{k-1}}{k}
    這一項是最簡單的,我們只用一個配湊組合數的技巧就能搞定,數學競賽也經常用
    (n1k1)k=1k(n1)!(k1)!(nk)!=1nn!k!(nk)!=(nk)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}

  • (n1k1)k2\frac{\tbinom{n-1}{k-1}}{k^2} 差分。。。

有點晚了,未完待續。。。

C. 組合計數題

link

  • 先按右端點排序
  • 對於每個區間求出它最左邊能碰到的一個區間,和最右邊能碰到的一個區間
  • 然而我們只考慮這兩個邊界就行了,問題變成了,一些區間,其中選一些出來使得並集是全集,這個dp可以用線段樹維護
T1賽後代碼
#include<bits/stdc++.h>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章