您的位置:首页 > 其它

2017年8月18日提高组T2 队伍统计

2017-09-03 20:55 148 查看

Description

现在有n个人要排成一列,编号为1->n 。但由于一些不明原因的关系,人与人之间可能存在一些矛盾关系,具体有m条矛盾关系(u,v),表示编号为u的人想要排在编号为v的人前面。要使得队伍和谐,最多不能违背k条矛盾关系(即不能有超过k条矛盾关系(u,v),满足最后v排在了u前面)。问有多少合法的排列。答案对10^9+7取模。

Input

输入文件名为count.in。

第一行包括三个整数n,m,k。

接下来m行,每行两个整数u,v,描述一个矛盾关系(u,v)。

保证不存在两对矛盾关系(u,v),(x,y),使得u=x且v=y 。

Output

输出包括一行表示合法的排列数。

Hint

对于30%的数据,n<=10

对于60%的数据,n<=15

对应100%的数据,n,k<=20,m<=n*(n-1),保证矛盾关系不重复。

Source

BMP

Solution

n、k很小,考虑状压dp

设f[i][j]表示选了人的二进制状态为i,j对矛盾关系的排列数。我们根据给定的矛盾关系用二进制rec[i]记录第i人与哪些人不合,然后or一下就可以了

这样直接做是有可能t的,因此枚举状态的时候可以提前判断continue

Code

#include <stdio.h>
#include <string.h>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define min(x, y) (x)<(y)?(x):(y)
#define MOD 1000000007
#define N 21
int t
, f[1<<N]
, bnr[1<<N], xjh[1<<N];
__attribute__((optimize("O2")))
inline int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') {ch = getchar();}
while (ch <= '9' && ch >= '0') {x = x * 10 + ch - '0'; ch = getchar();}
return x;
}
__attribute__((optimize("O2")))
inline void writeln(int x) {
int prt[32] = {};
do {prt[++ prt[0]] = x % 10;}while (x /= 10);
for (int i = prt[0]; i >= 1; i -= 1) {putchar((char)(prt[i]+'0'));}
puts("");
}
__attribute__((optimize("O2")))
inline int count(int x) {
int cnt = 0;
for (; x > 0; x -= x&(-x), cnt += 1);
return cnt;
}
__attribute__((optimize("O2")))
int main(void) {
int n = read();
int m = read();
int k = read();
rep(i, 1, m) {
t[read()] |= 1<<read()-1;
}
f[0][0] = 1;
int lim = (1 << n) - 1;
rep(i, 0, lim) {xjh[i] = count(i);}
rep(i, 1, lim) {
rep(l, 1, n) {
if ((i&(1<<l-1))!=(1<<l-1)) {continue;}
rep(j, 0, k) {
if (j >= xjh[t[l]&i]) {(f[i][j] += f[i^(1<<l-1)][j-xjh[t[l]&i]])%=MOD;}
}
}
}
int ans = 0;
rep(i, 0, k) {(ans += f[lim][i])%=MOD;}
writeln(ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: