题意:给定 n 和k,n 表示有n个房子,然后每个有一个编号,一只鹅要从一个房间中开始走,下一站就是房间的编号,现在要你求出有多少种方法编号并满足下面的要求:
1.如果从1-k房间开始走,一定能直到 1。
2.如果从k+1到n 开始走,一定走不到 1.
3.如果从 1 开始走,那么一定能回到1,并且走过房间数不为0.
析:这个题,当时想了好久,其实并不难,当时是暴力过的,一看 k 最大才是8,那么应该不会TLE,然后就暴力了。首先这前 k 个数和后面的数,完全没有关系,
后面就是 n-k的 n-k次方,关键是前面,我们可以一个一个的试,并判断会不会成立,用DFS即可。
这个题可以用快速幂来做。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1000000 + 5; const int INF = 0x3f3f3f3f; const int mod = 1000000007; const int dr[] = {0, 0, 1, -1}; const int dc[] = {1, -1, 0, 0}; int cnt, k; int a[100]; set<int> ss; bool judge(int u, int rt){ if(a[u] == 1) return true; if(a[u] != rt && u != a[u] && a[u] && !ss.count(u)){ ss.insert(u); return judge(a[u], rt); } return false; } void dfs(int cur){ if(cur == k+1){ for(int i = 2; i <= k; ++i){ ss.clear(); if(!judge(i, i)) return ; } ++cnt; return ; } for(int i = 1; i <= k;++i){ a[cur] = i; dfs(cur+1); } return ; } int qickpow(LL a, LL b){ LL k = a; LL ans = 1; while(b){ if(b & 1){ ans = (ans * k) % mod; } k = (k * k) % mod; b >>= 1; } return (int) ans; } int main(){ int ans; int n; scanf("%d %d", &n, &k); int t = n - k; ans = qickpow(n-k, n-k); cnt = 0; dfs(2); ans = (ans * k * cnt) % mod; cout << ans << endl; return 0; }
方法二:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1000000 + 5; const int INF = 0x3f3f3f3f; const int mod = 1000000007; const int dr[] = {0, 0, 1, -1}; const int dc[] = {1, -1, 0, 0}; int cnt, k; int qickpow(LL a, LL b){ LL k = a; LL ans = 1; while(b){ if(b & 1){ ans = (ans * k) % mod; } k = (k * k) % mod; b >>= 1; } return (int) ans; } int main(){ int ans; int n; scanf("%d %d", &n, &k); int t = n - k; ans = qickpow(n-k, n-k); cnt = 0; LL ans1 = qickpow(k, k-1); ans = (ans * ans1) % mod; cout << ans << endl; return 0; }