USACO 6.5 All Latin Squares
A square arrangement of numbers
1 2 3 4 5 2 1 4 5 3 3 4 5 1 2 4 5 2 3 1 5 3 1 2 4
is a 5 x 5 Latin Square because each whole number from 1 to 5 appears once and only once in each row and column.
Write a program that will compute the number of NxN Latin Squares whose first row is:
1 2 3 4 5.......N
Your program should work for any N from 2 to 7.
PROGRAM NAME: latin
INPUT FORMAT
One line containing the integer N.
SAMPLE INPUT (file latin.in)
5
OUTPUT FORMAT
A single integer telling the number of latin squares whose first row is 1 2 3 . . . N.
SAMPLE OUTPUT (file latin.out)
1344
————————————————————题解
第一行已经固定了,如果我们固定第一列为1 2 3 4 5……n 那么我们计算出的方案数乘以(n-1)!即可
然后这个优化加上位运算也只能过6。7就很尴尬了。
还有一个神一般的优化
例如
1 2 3 4 5
2 1 4 3 5
这其中有两个置换圈 1,2 和 3,4,5
如果再来一种搜索搜到了
1 2 3 4 5
2 3 1 5 4
这其中有两个置换圈 1 2 3 和 4 5
注意到了吗这个置换圈要先从大到小排序
这样的话其实这两种情况是等价的
为什么等价?
长度为2的两个圈 1 2 和 4 5可以分别一一对应
长度为3的两个圈3 4 5 和 1 2 3可以分别一一对应
也就是像我们手里得到了一张转换表,把第一种情况里的后四排的
1写成4
2写成5
3写成1
4写成2
5写成3
最后得到了一个新的拉丁方格
所以我们用一个哈希表记录置换圈的长度和所有置换圈长度的乘积,算过一遍的方案直接得出,节省很多时间……
orz反正我是想不到的
1 /* 2 LANG: C++ 3 PROG: latin 4 */ 5 #include <iostream> 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring> 9 #include <cmath> 10 #define siji(i,x,y) for(int i=(x); i<=(y) ; ++i) 11 #define ivorysi 12 #define o(x) ((x)*(x)) 13 using namespace std; 14 typedef long long ll; 15 int n; 16 int col[10],row[10],num[10][10]; 17 bool v[10]; 18 ll ans,h[50][5];//置换圈的长度乘积,个数 19 void init() { 20 scanf("%d",&n); 21 siji(i,1,n) { 22 num[1][i]=i; 23 num[i][1]=i; 24 col[i]=(1<<i); 25 row[i]=(1<<i); 26 } 27 memset(h,-1,sizeof(h)); 28 } 29 30 ll dfs(int x,int y) { 31 if(x>=n){ 32 return 1; 33 } 34 ll res=0; 35 if(x==3&&y==2) { 36 memset(v,0,sizeof(v)); 37 int cnt=0,len=1; 38 siji(i,1,n) { 39 if(v[i]) continue; 40 v[i]=1; 41 int rec=1; 42 for(int l=num[2][i];l!=i;l=num[2][l]) { 43 v[l]=1; 44 ++rec; 45 } 46 len*=rec; 47 ++cnt; 48 } 49 if(h[len][cnt]!=-1) return h[len][cnt]; 50 siji(i,1,n) { 51 if(((col[y]&(1<<i))==0) && ((row[x]&(1<<i))==0)) { 52 col[y]|=(1<<i); 53 row[x]|=(1<<i); 54 num[x][y]=i; 55 if(y==n) res+=dfs(x+1,2); 56 else res+=dfs(x,y+1); 57 col[y]^=(1<<i); 58 row[x]^=(1<<i); 59 num[x][y]=0; 60 } 61 } 62 return h[len][cnt]=res; 63 } 64 siji(i,1,n) { 65 if(((col[y]&(1<<i))==0) && ((row[x]&(1<<i))==0)) { 66 col[y]|=(1<<i); 67 row[x]|=(1<<i); 68 num[x][y]=i; 69 if(y==n) res+=dfs(x+1,2); 70 else res+=dfs(x,y+1); 71 col[y]^=(1<<i); 72 row[x]^=(1<<i); 73 num[x][y]=0; 74 } 75 } 76 return res; 77 } 78 void solve() { 79 init(); 80 //if(n==7) {cout<<"12198297600"<<endl;return;} 81 ans=dfs(2,2); 82 siji(i,1,n-1) ans*=i; 83 printf("%lld\n",ans); 84 } 85 int main(int argc, char const *argv[]) 86 { 87 #ifdef ivorysi 88 freopen("latin.in","r",stdin); 89 freopen("latin.out","w",stdout); 90 #else 91 freopen("f1.in","r",stdin); 92 //freopen("f1.out","w",stdout); 93 #endif 94 solve(); 95 return 0; 96 }