10-22 訓練 T2 plate


10-22 訓練 T2 plate

傳送門

題目大意

有N個圓盤,每個圓盤的圓周上均勻分布了P個點(可連成正P邊形),編號\(P_1\)\(P_n\)。這P個點 中有M個關鍵點,所有關鍵點都是相同的。給出每個圓盤關鍵點位置的數據(對應的 \(P_i\)),現在 可以隨意轉動圓盤,問有多少對圓盤最終可以變成相同的形態。

思路

我們想要對兩個序列進行比較,由於編號不一樣,很明顯想到比較間距。但是間距數列的首項不固定,如果在所有數列的循環同構(把數列首尾接成環,所有的展開而成數列都是循環同構)中暴力比較,復雜度為 \(O(n^2)\) ,不太 \(OK\) 。這時就出現了一個神奇的算法:最小表示。

通過最小表示將序列按間距的字典序最小的方式排列,然后 \(O(n)\) 就可以比較了。

於是重點變成了如何以 \(O(n)\) 處理最小表示。

最小表示法

將數列 \(A\) 復制一份塞在其后來模擬環結構。

定義兩個指針 \(i\)\(j\) (初始為 \(1\)\(2\))記錄兩個長度為 \(m\) 的數列的開頭,定義 \(k\) 為正在比較的位置距列首的距離。遍歷 \(k\),當比較發現 \(A_{i+k}\)\(A_{j+k}\) 有差別時(這里不妨設是\(A_{i+k}< A_{j+k}\) ),說明\(A_{j},A_{j+1},A_{j+2},\dots,A_{j+k}\) 都不會是最小表示,那么我們將 \(j\) 跳到 \(j+k+1\) ,並且如果 \(j=i\) 時,我們將 \(j\) 再加一以保證比較的是兩個不一樣的排列。

如過 \(k\) 遍歷到了 \(m\),說明兩個排列完全相等,由於我們保證了不對比兩個一樣的排列,說明這時數列中的元素全部是一樣的。這時跳出函數以任意點做起點就行了。

如果 \(i\)\(j\) 有一個超過了 \(m\) 那么所有的排列都被比較完了,那么仍在 \(m\) 范圍內的那個指針就作為數列的起點。

Code

#include<cstdio>
#include<algorithm>
using namespace std;

int n,m,p,ans;
int a[501][1001],dis[501][1001];
int st[501],num[501],fa[501];

int findd(int x){
	if(x!=fa[x]) return fa[x]=findd(fa[x]);
	else return fa[x];
}

void add(int x,int y){
	int anx=findd(x),any=findd(y);
	if(anx==any) return ;
	ans+=num[x];
	num[x]+=num[y];
	num[y]=0;
	fa[any]=anx; 
}


int main()
{
	scanf("%d %d %d",&n,&m,&p);
	for(int i=1;i<=n;i++){
		fa[i]=i;
		num[i]=1;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
		}
        sort(a[i]+1,a[i]+1+m);
        for(int j=2;j<=m;j++){
        	dis[i][j-1]=a[i][j]-a[i][j-1];
		}
		dis[i][m]=a[i][1]-a[i][m]+p; 
		for(int j=1;j<=m;j++){
			dis[i][m+j]=dis[i][j];
		}
		int x=1,y=2,k=0;
		while(x<=m && y<=m){
			while(k<m && dis[i][x+k]==dis[i][y+k]) k++;
			if(k==m) break;
			if(dis[i][x+k] > dis[i][y+k]){
				x=x+k+1;
				k=0;
				if(x==y) x++;
			}
			else{
				y=y+k+1;
				k=0;
				if(x==y) y++;
			}
		}
	    st[i]=min(x,y);
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			int flag=1;
			for(int l=0;l<m;l++){
				if(dis[i][st[i]+l] != dis[j][st[j]+l]){
					flag=0;
					break;
				}
			}
			if(flag){
				add(i,j);
			}
		}
	}
	printf("%d",ans);
	return 0;
}

最后統計答案做法很多,讀者可以考慮別的做法。

\(\beta y\quad\_thorn\)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM