HDU-6038 Function

来源:互联网 发布:谜踪之国全文解密知乎 编辑:程序博客网 时间:2024/06/05 14:08

题意:给出两个排列,a和b,求满足映射的f[i] = bf[a[i]]的个数。

思路:

one. 列出所有式子,进行连边,一个环中某一个元素一旦确定,其它也就确定了,所以需要求强连通分量,要想能够构成一个k个元素的强连通分量,只有m个数中的连环数个数为k的因子时才能够构成。然后再对所有连通分量的方案数进行乘积。

two. 用置换群的思想,通过f函数构造一个新的置换,然后找到构造的置换和m个数置换的轮换即一个环进行操作即可。


代码1:

#include <algorithm>#include <string.h>#include <cstdio>#include <map>#define LL long longusing namespace std;const LL mod = 1e9+7;const int maxn = 1e5+5;const int maxm = maxn;struct node{int v, next;} edge[maxm];int no, head[maxn];int n, m;int index, top, num[maxn], low[maxn], book[maxn], S[maxn];int a[maxn], b[maxn];int vis[maxn], circle[maxn];map<int, int> mp;map<int, int>::iterator it;LL ans, final;inline void init(){mp.clear();no = 0; index = 0; top = 0;memset(head, -1, sizeof head);memset(book, 0, sizeof book);memset(circle, 0, sizeof circle);memset(num, 0, sizeof num);memset(vis, 0, sizeof vis);}inline void add(int u, int v){edge[no].v = v; edge[no].next = head[u];head[u] = no++;}void tarjan(int cur){num[cur] = low[cur] = ++index;vis[cur] = 1; S[++top] = cur;for(int k = head[cur]; k != -1; k = edge[k].next){if(!num[edge[k].v]){tarjan(edge[k].v);low[cur] = min(low[cur], low[edge[k].v]);}else if(vis[edge[k].v]){low[cur] = min(low[cur], num[edge[k].v]);}}if(num[cur] == low[cur]){int cnt = 0;do{++cnt;vis[S[top]] = 0;--top;}while(S[top+1] != cur);++mp[cnt];}}int main(){int count = 0;while(~scanf("%d %d", &n, &m)){init(); final = 1;for(int i = 0; i < n; ++i) scanf("%d", &a[i]);for(int i = 0; i < m; ++i) scanf("%d", &b[i]);for(int i = 0; i < m; ++i){if(book[i]) continue;int k = b[i], cnt = 1;while(k != i) ++cnt, k = b[k];k = b[i]; book[i] = 1; ++circle[cnt];while(k != i) ++circle[cnt], book[k] = 1, k = b[k];}for(int i = 0; i < n; ++i) add(a[i], i);for(int i = 0; i < n; ++i) if(!num[i]) tarjan(i);for(it = mp.begin(); it != mp.end(); ++it){int i, k = it->first, t = it->second;ans = 0;ans = (ans+(LL)circle[1])%mod;for(i = 2; i*i < k; ++i){if(k%i == 0){ans = (ans+(LL)circle[i])%mod;ans = (ans+(LL)circle[k/i])%mod;}}if(k%i==0 && k/i == i) ans = (ans+(LL)circle[i])%mod;if(k > 1) ans = (ans+(LL)circle[k])%mod;for(int j = 1; j <= t; ++j) final = final*ans%mod;}printf("Case #%d: %lld\n", ++count, final);}return 0;}


代码2:

#include <algorithm>  #include <string.h>  #include <cstdio>  #include <map>  #define LL long long  using namespace std;  const LL mod = 1e9+7;  const int maxn = 1e5+5; int n, m;int a[maxn], b[maxn], gz[maxn];  int vis[maxn], cir1[maxn];  map<int, int> mp;  map<int, int>::iterator it;  LL ans, final;int main()  {      int count = 0;      while(~scanf("%d %d", &n, &m))      {           memset(cir1, 0, sizeof cir1);        memset(vis, 0, sizeof vis); final = 1;         for(int i = 0; i < n; ++i) scanf("%d", &a[i]);          for(int i = 0; i < m; ++i) scanf("%d", &b[i]);          for(int i = 0; i < m; ++i)          {              if(vis[i]) continue;              int k = b[i], cnt = 1;              while(k != i) ++cnt, k = b[k];              k = b[i]; vis[i] = 1; ++cir1[cnt];              while(k != i) ++cir1[cnt], vis[k] = 1, k = b[k];          }memset(vis, 0, sizeof vis); mp.clear();        for(int i = 0; i < n; ++i) gz[a[i]] = i;         for(int i = 0; i < n; ++i)          {              if(vis[i]) continue;              int k = gz[i], cnt = 1;              while(k != i) ++cnt, k = gz[k];              k = gz[i]; vis[i] = 1;             while(k != i) vis[k] = 1, k = gz[k]; ++mp[cnt];        }        for(it = mp.begin(); it != mp.end(); ++it)        {              int i, k = it->first, t = it->second;              ans = 0;              ans = (ans+(LL)cir1[1])%mod;              for(i = 2; i*i < k; ++i)              {                  if(k%i == 0)                  {                      ans = (ans+(LL)cir1[i])%mod;                      ans = (ans+(LL)cir1[k/i])%mod;                  }              }              if(k%i==0 && k/i == i) ans = (ans+(LL)cir1[i])%mod;              if(k > 1) ans = (ans+(LL)cir1[k])%mod;              for(int j = 1; j <= t; ++j) final = final*ans%mod;        }          printf("Case #%d: %lld\n", ++count, final);      }      return 0;  }

继续加油~