HDU 6038 Function(思维+寻找循环节)
Posted 谦谦君子,陌上其华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6038 Function(思维+寻找循环节)相关的知识,希望对你有一定的参考价值。
http://acm.hdu.edu.cn/showproblem.php?pid=6038
题意:
给出两个序列,一个是0~n-1的排列a,另一个是0~m-1的排列b,现在求满足的f的个数。
思路:
先看一下样例吧:
对于这组数来说,假如我们先指定了f(0)对应的在b中的值,那么根据第2个式子,就可以得出f(1),根据f(1)就又可以得出f(2),最后根据f(2)就可以检验f(0)的值是否正确。
这也就是说,对于a中的一个循环节,只要确定了其中一个数所映射的值,那么其它数就都被相应的确定了。
所以我们需要先计算出a和b中的循环节个数和每个循环节对应的个数,然后根据循环节的因子关系就可以判断是否成立。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,int> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn = 1e5 + 5; 17 const int mod = 1e9+7; 18 19 int n, m; 20 21 int a[maxn], b[maxn]; 22 int vis[maxn]; 23 24 vector<int> A; 25 vector<int> B; 26 27 int main() 28 { 29 //freopen("in.txt","r",stdin); 30 int kase=0; 31 while(~scanf("%d%d",&n,&m)) 32 { 33 for(int i=0;i<n;i++) scanf("%d",&a[i]); 34 for(int i=0;i<m;i++) scanf("%d",&b[i]); 35 36 A.clear(); 37 memset(vis,0,sizeof(vis)); 38 for(int i=0;i<n;i++) 39 { 40 int cur=i,cnt=1; 41 if(!vis[i]) 42 { 43 vis[i]=1; 44 while(a[cur]!=i) 45 { 46 cur=a[cur]; 47 vis[cur]=1; 48 cnt++; 49 } 50 A.push_back(cnt); 51 } 52 } 53 54 B.clear(); 55 memset(vis,0,sizeof(vis)); 56 for(int i=0;i<m;i++) 57 { 58 int cur=i, cnt=1; 59 if(!vis[i]) 60 { 61 vis[i]=1; 62 while(b[cur]!=i) 63 { 64 cur=b[cur]; 65 vis[cur]=1; 66 cnt++; 67 } 68 B.push_back(cnt); 69 } 70 } 71 72 ll ans=1; 73 for(int i=0;i<A.size();i++) 74 { 75 ll tmp=0; 76 for(int j=0;j<B.size();j++) 77 { 78 if(A[i]%B[j]==0) tmp=(tmp+B[j])%mod; 79 } 80 ans=ans*tmp%mod; 81 } 82 printf("Case #%d: %d\\n",++kase,ans); 83 } 84 return 0; 85 }
以上是关于HDU 6038 Function(思维+寻找循环节)的主要内容,如果未能解决你的问题,请参考以下文章