URAL 1747 Kingdom Inspection 容斥原理
2014-07-27 21:33
274 查看
题目大意:
从前有一个王国有着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;
}
从前有一个王国有着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;
}
相关文章推荐
- URAL 1091 Tmutarakan Exams(容斥原理)
- Ural 1091 Tmutarakan Exams [容斥原理]
- URAL 1091. Tmutarakan Exams(容斥原理)
- ural 1932 The Secret of Identifier (容斥原理)
- SYSU-10,URAL 1675,容斥原理
- 数学分析 + 容斥原理 - URAL 1907 Coffee and Buns
- 数学分析 + 容斥原理 - URAL 1907 Coffee and Buns
- 【URAL】1091 Tmutarakan Exams (简单容斥原理)
- URAL1091 Tmutarakan Exams (容斥原理)
- hdu 1695 GCD 容斥原理 ural 1091
- ural 1932 The Secret of Identifier (容斥原理)
- URAL 1907. Coffee and Buns(数论推导+容斥原理)
- Ural 1091 Tmutarakan Exams【容斥原理】
- Ural 1091 Tmutarakan Exams 解题报告(容斥原理)
- ural 1881
- URAL 1083. Factorials!!!
- HDOJ-----4135Co-prime容斥原理三种实现
- ural 1277. Cops and Thieves【最小割】
- [Ural 1039] 没有上司的晚会
- Ural 1449 Credit Operations 2