D题, 纠结, 一开始想用组合数学的方法可是想不出怎么排列组合, 然后又准备暴力结果发现普通暴力在n=15的时候就不知道要运行多少时间。。。
于是去学习了一个 中途相遇的 搜索算法,快了很多, n=15的那组数据也可以在20s内跑完.
其实这个算法就是将 n^n 的复杂度变成了 2*n^(n/2) , 可以快很多....
本质就是将整个搜索过程分成两半来搜。
Permutation p is an ordered set of integers p1, p2, ..., pn, consisting of n distinct positive integers, each of them doesn't exceed n. We'll denote the i-th element of permutation p as pi. We'll call number n the size or the length of permutation p1, p2, ..., pn.
Petya decided to introduce the sum operation on the set of permutations of length n. Let's assume that we are given two permutations of length n: a1, a2, ..., an and b1, b2, ..., bn. Petya calls the sum of permutations a and b such permutation c of length n, where ci = ((ai - 1 + bi - 1) mod n) + 1 (1 ≤ i ≤ n).
Operation means taking the remainder after dividing number x by number y.
Obviously, not for all permutations a and b exists permutation c that is sum of a and b. That's why Petya got sad and asked you to do the following: given n, count the number of such pairs of permutations a and b of length n, that exists permutation c that is sum of a and b. The pair of permutations x, y (x ≠ y) and the pair of permutations y, x are considered distinct pairs.
As the answer can be rather large, print the remainder after dividing it by 1000000007 (109 + 7).
The single line contains integer n (1 ≤ n ≤ 16).
In the single line print a single non-negative integer — the number of such pairs of permutations a and b, that exists permutation c that is sum of a and b, modulo 1000000007 (109 + 7).
3
18
5
1800
#include <stdio.h> #include <string.h> #include <iostream> using namespace std; #define MOD 1000000007 typedef __int64 LL; int n; int n1,n2; int g1[20],g2[20]; int key; int cnt1,cnt2; LL sum1[1<<17],sum2[1<<17]; int pan(int i,int k) { int sum=0; while(i) { sum += i&1; i=i>>1;; } return sum==k; } void dfs1(int s) { if(s>n1) { sum1[key]++; return ; } for(int i=0;i<cnt1;i++) { int tmp=g1[i]; if(g1[i]==-1) continue; int tmp1=(tmp+s-2)%n+1; if(key & ( 1<<(tmp1-1) ) ) continue; key |= ( 1<<(tmp1-1) ); g1[i]=-1; dfs1(s+1); g1[i]=tmp; key ^= ( 1<<(tmp1-1) ); } } void dfs2(int s) { if(s>n) { sum2[key]++; return ; } for(int i=0;i<cnt2;i++) { int tmp=g2[i]; if(g2[i]==-1) continue; int tmp1=(tmp+s-2)%n+1; if(key & ( 1<<(tmp1-1) ) ) continue; key |= ( 1<<(tmp1-1) ); g2[i]=-1; dfs2(s+1); g2[i]=tmp; key ^= ( 1<<(tmp1-1) ); } } int main() { for(int i=1;i<=16;i++) { n=i; n1=n/2; n2=n-n1; LL ans=0; for(int i=0;i<=(1<<n)-1;i++) { if(pan(i,n1)==0) continue; cnt1=0; cnt2=0; for(int j=0;j<n;j++) { if( (1<<j)&i ) g1[cnt1++]=j+1; else g2[cnt2++]=j+1; } memset(sum1,0,sizeof(sum1)); memset(sum2,0,sizeof(sum2)); key=0; // 主要用来记录c的情况... dfs1(1); key=0; dfs2(n1+1); for(int j=0;j<=(1<<n)-1;j++) { int tmp=j^((1<<n)-1); ans=(ans+(sum1[j]*sum2[tmp])%MOD)%MOD; } } for(int i=1;i<=n;i++) ans=(ans*i)%MOD; printf("%I64d,",ans); } return 0; } /*#include <stdio.h> int g[20]={0,1,0,18,0,1800,0,670320,0,734832000,0,890786230,0,695720788,0,150347555,0}; int main() { int n; scanf("%d",&n); printf("%d",g[n]); }*/