题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3687
题意:有N天和N个章节,每天可以完成一个章节,有M个限制,表示第Di天不能完成章节Ci。
问共有多少种计划方案可以完成所有章节。
思路:
这题就是禁位排列的裸题了。
禁位排列的公式:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int N, M; 4 #define maxn 55 5 #define mod 55566677 6 struct Node 7 { 8 int D, C; 9 Node(int dd, int cc){D = dd; C = cc;} 10 }; 11 vector <Node> node; 12 int mark[maxn][maxn]; 13 int visd[maxn], visc[maxn]; 14 long long num[maxn]; 15 long long ans; 16 void init() 17 { 18 num[0] = 1; num[1] = 1; 19 for(int i = 2; i <= 50; i++) 20 { 21 num[i] = num[i-1]*i%mod; 22 } 23 } 24 void dfs(int pos, int cnt) 25 { 26 if(pos > M) 27 { 28 if(cnt%2) ans = ((ans - num[N-cnt])%mod + mod)%mod; 29 else ans = (ans + num[N-cnt])%mod; 30 return; 31 } 32 dfs(pos+1, cnt); 33 if(!visd[node[pos].D] && !visc[node[pos].C]) 34 { 35 visd[node[pos].D] = visc[node[pos].C] = 1; 36 dfs(pos+1, cnt+1); 37 visd[node[pos].D] = visc[node[pos].C] = 0; 38 } 39 } 40 int main() 41 { 42 // freopen("in.txt", "r", stdin); 43 init(); 44 while(~scanf("%d%d", &N, &M)) 45 { 46 node.clear(); 47 memset(mark, 0, sizeof(mark)); 48 node.push_back(Node(-1, -1)); 49 for(int i = 1; i <= M; i++) 50 { 51 int d, c; scanf("%d%d", &d, &c); 52 if(!mark[d][c]) 53 { 54 mark[d][c] = 1; 55 node.push_back(Node(d, c)); 56 } 57 } 58 M = node.size()-1; 59 ans = 0; 60 memset(visc, 0, sizeof(visc)); 61 memset(visd, 0, sizeof(visd)); 62 dfs(1, 0); 63 printf("%lld\n", ans); 64 } 65 return 0; 66 }
时间: 2024-10-14 04:51:28