Function

来源:互联网 发布:java带类路径启动 编辑:程序博客网 时间:2024/06/05 16:11

Function

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1472    Accepted Submission(s): 691


Problem Description
You are given a permutation a from 0 to n1 and a permutation b from 0 to m1.

Define that the domain of function f is the set of integers from 0 to n1, and the range of it is the set of integers from 0 to m1.

Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n1.

Two functions are different if and only if there exists at least one integer from0 to n1 mapped into different integers in these two functions.

The answer may be too large, so please output it in modulo 109+7.
 

Input
The input contains multiple test cases.

For each case:

The first line contains two numbers n,m.(1n100000,1m100000)

The second line contains n numbers, ranged from 0 to n1, the i-th number of which represents ai1.

The third line contains m numbers, ranged from 0 to m1, the i-th number of which represents bi1.

It is guaranteed that n106,m106.
 

Output
For each test case, output "Case #x:y" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
 

Sample Input
3 21 0 20 13 42 0 10 2 3 1
 

Sample Output
Case #1: 4Case #2: 4
  
题目大意:
       有a,b两个数组,它们之间满足f(i)=b(a(i)),求有多少种赋值方法。
思路:
       因为数组a可以与函数f的顺序构成关系,所以就把a固定,把b一一对应进去。这样就转化成一个循环问题,通过举例我们可以看出,我们需要先求出数组a与b的各个循环节的长度及个数,如果b的循环节长度不是a的循环节长度的因子,则不计入计算,我们只考虑b的循环节长度是a的循环节长度的因子的情况。最后结果等于所有为a循环节长度因子的b的循环节的长度乘以这个循环节的个数,再乘有多少这种循环节长度的循环。下面举例说明。
       7 6
       3 2 0 1 5 6 4
       1 0 3 4 2 5
       由此例可知,a的循环节有,(3 2 0 1)长度为4,个数为1;(5 6 4)长度为3,个数为1。b的循环节有,(1 0)长度为2,个数为1;(3 4 2)长度为3,个数为1;(5)长度为1,个数为1。其中1,2为4的因子;1,3为3的因子。则结果为(1*1+2*1)*(1*1+3*1)=3*4=12。
下面贴上代码:(具体实现过程及优化方法详解见代码注释)
#include<cstdio>#include<iostream>#include<cstring>#include<cmath>using namespace std;#define ll  long long#define Mod 1000000007const int maxn=1e5+5;ll circle[3][maxn]; //circle[a或者b][length]=个数int a[maxn],b[maxn];int main(){    int n,m;    int ca=1;    while(~scanf("%d %d",&n,&m)) //注意使用scanf,用cin会超时    {        memset(circle,0,sizeof circle);        memset(a,0,sizeof a);        memset(b,0,sizeof b);        for(int i=0; i<n; i++)            scanf("%d",&a[i]);        for(int i=0; i<n; i++)        {            ll k=i;            ll length=0;            while(a[k]!=-1) //若当前位置为-1,说明已经查找过,形成循环            {                length++; //length记录循环节的长度                int t=k; //t为当前查找的位置                k=a[k]; //根据a[位置]=下一个位置,查找下一个位置                a[t]=-1; //把查找到的位置标记为-1            }            if(length!=0)                circle[1][length]++; //记录a数组中长度为length的循环节个数        }        for(int i=0; i<m; i++)            scanf("%d",&b[i]);        for(int i=0; i<m; i++)        {            ll k=i;            ll length=0;            while(b[k]!=-1)            {                length++;                int t=k;                k=b[k];                b[t]=-1;            }            if(length!=0)                circle[2][length]++; //记录b数组中长度为length的循环节个数        }        long long ans=1;        for(int i=1; i<=n; i++)        {            if(circle[1][i]!=0)            {                int lim=(int)sqrt(i+0.5),sum=0;//稍微优化                for(int j=1; j<=lim; j++)                {                    if(i%j==0) //a的循环节长度能够整除b的循环节长度                    {                        sum=sum+circle[2][j]%Mod*j%Mod;                        //a的其中一个循环节在b中的各个因子计算:(长度为w)循环节个数*(w)循环节长度,再取和                        sum=sum%Mod;                        if(j*j!=i)                        {                            sum=sum+circle[2][i/j]%Mod*(i/j)%Mod;                            sum=sum%Mod;                        }                    }                }                for(int j=1; j<=circle[1][i]; j++)                {                    ans=ans*sum; //将所有sum相乘得结果                    ans=ans%Mod;                }            }        }        cout<<"Case #"<<ca++<<": "<<ans<<endl;    }}