题目大意:
从前有一个王国有着n个城镇,其中国王住在首都里(首都只有1个),现在国王想要从首都出发,经过每个其他城市正好两次后回到首都,问有多少种走法
对于任意的两个城市,都有一条双向的路相连
大致思路:
由于任意两个城市都有路相连,整个地图就是一个有着n个顶点的完全图,我们假设从编号为1的顶点处发后回到顶点,那么真个路线就是2*n个数的排列
其中首尾都是1,中间2,3,4.... n等都是2个,
那么有多少种不同的路线的问题,就是给出数字 编号2 到 n 的点各有两个,能组成多少种不同的排列的问题
那么就是2*k个物品, 分别是1,2,3,4...到k各2个,一共有多少种不同的排列( k = n - 1, 对应的便是原题的答案)
假设条件Si 表示编号为i 的两个数在一起(相邻)
那么答案就是Card((!S1) && ( !S2 ) && ( !S3 ) && ... && (!Sk) )
也就是 A(2*k , 2*k) - Card(S1 || S2 || S3 || S4 || ... || Sk)
根据容斥原理可以知道:
这里就涉及到一个问题,由于原题要求取模输出,考虑到分母的2^(k - i), 这里需要做一点处理
这里的一个技巧就是,i*(2*k - i + 1) / 2这个式子中, i 和 (2*k - i + 1) 之中一定会有一个数能够整除2,那么这样就可以整体取模了
这样直接跑一下循环求出 h[ i ]即可
接下来是代码:
Result : Accepted Memory : 1947 KB Time : 31 ms
/* * Author: Gatevin * Created Time: 2014/7/25 16:42:08 * File Name: test.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn 1000100 lint n,mod; lint f[maxn]; lint g[maxn]; int main() { cin>>n>>mod; lint k = n - 1; f[0] = 1; g[k] = 1; for(int i = 1; i <= k; i++) { f[i] = f[i - 1]*(k - i + 1) % mod; } for(int i = k; i >= 1; i--) { g[i - 1] = (g[i]*((2*k - i + 1)*i/2)%mod) % mod; } lint answer = 0; for(int i = 0; i <= k; i++) { if(i & 1) answer = (answer - (f[i]*g[i]) % mod + mod) % mod; else answer = (answer + (f[i]*g[i]) % mod + mod) % mod; } cout<<answer<<endl; return 0; }