【HDU 6038】Function(图+组合数学)

来源:互联网 发布:淘宝该怎么做 编辑:程序博客网 时间:2024/06/05 08:46

题目链接:hdu6038

题目大意:a数组有n个元素(0 ~ n-1),b数组有m个元素(0 ~ m-1),定义一个函数 f ,使 f(i) = b[f(ai)],求满足条件的 f  函数有多少种

                 例如     3   2
                      a     1   0   2                f (0) = b [f(1)]                        所以可能的结果有 4   (2*2) 种,
                      b     0   1                     f (1) = b [f(0)]                        ① f (0) = f (1) = 0   或   f (0) = f (1) = 1

                                                         f (2) = b [f(2)]                        ② f (2) = 0    或    f (2) = 1 


思路:a 和 b 中的每个元素都属于一个环,可以发现只有当 b 里环数为 a 里环数 的因数时,可以将 b 环中的值填入 a 环里,对于 b 环,每个环的元素个数就是这个环填入一个a环时的情况数(举例可知),例如:a 形成的环(假设均为m个): 2 环, 3 环,4 环;  b 形成的环(假设均为k个): 1 环,2 环, 3 环, 4 环。则将b环中的数填入a环中:

                                      2 环(a)里包含: 1、2环 (b) ,        每个环有    1*k1 + 2*k2  种情况, 则 m 个环共有    (1*k1 + 2*k2 )^ m1  种情况

                                      3 环包含 1、3环;    4 环包含1、2、4环

CODE:

#include <cstdio>#include <cstring>#include <map>#include <vector>#include <string>#include <algorithm>#define maxn 100005#define mod (1000000000+7)typedef long long ll;using namespace std;ll mp[2][maxn];ll vis[maxn], f[maxn];ll fun(ll x, ll n){ll ans = 1;while (n) {if (n & 1) ans = (ans*x) % mod;x = x*x%mod;n >>= 1;}return ans;}void Ring(int n, int u){memset(vis, 0, sizeof(vis));for (int i = 0; i < n; i++)scanf("%lld", &f[i]);for (int i = 0; i < n; i++) {int k = i, cot = 0;if (k == f[k] && !vis[k]) {mp[u][1]++;continue;}if (!vis[k]) {while (k != f[k] && !vis[k]) {vis[k] = 1;k = f[k];cot++;}if (k == f[k] && !vis[k])continue;mp[u][cot]++;}}}ll k[maxn],a[maxn],numa[maxn],b[maxn],numb[maxn];int main(){int n, m, cas = 1;while (~scanf("%d%d", &n, &m)) {memset(mp, 0, sizeof(mp));memset(k, 0, sizeof(k));Ring(n, 0);   //得到环,mp[0][k]表示a中k环的个数Ring(m, 1);   //mp[1][k]表示b中k环的个数ll ans = 1,cota = 1,cotb = 1;for (int i = 1; i <= n || i <= m; i++) {   //o(n)将所需的数列出,降低循环次数if (mp[0][i]) {a[cota] = mp[0][i];numa[cota++] = i;}if (mp[1][i]) {b[cotb] = mp[1][i];numb[cotb++] = i;}}for (int i = 1; i < cota; i++) {for (int j = 1; j < cotb; j++) {if (numa[i] % numb[j] == 0) {k[i] = (k[i]%mod + numb[j]*b[j] % mod) % mod;     //1个a环的所有情况加起来}}}for (int i = 1; i < cota; i++) {ans *= fun(k[i], a[i]);}printf("Case #%d: %lld\n", cas++, ans);}return 0;}


原创粉丝点击