Function
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 0 Accepted Submission(s): 0
Define that the domain of function f is the set of integers from 0 to n−1 , and the range of it is the set of integers from 0 to m−1 .
Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n−1 .
Two functions are different if and only if there exists at least one integer from 0 to n−1 mapped into different integers in these two functions.
The answer may be too large, so please output it in modulo 109+7 .
For each case:
The first line contains two numbers n, m . (1≤n≤100000,1≤m≤100000)
The second line contains n numbers, ranged from 0 to n−1 , the i -th number of which represents ai−1 .
The third line contains m numbers, ranged from 0 to m−1 , the i -th number of which represents bi−1 .
It is guaranteed that ∑n≤106, ∑m≤106 .
3 2 1 0 2 0 1 3 4 2 0 1 0 2 3 1
Case #1: 4 Case #2: 4
题目大意:
给你一个数组A,和一个数组B,数组A是【0~n-1】的排咧,数组B是【0~m-1】的排列。
现在定义F(i)=bF(ai);
问有多少种取值,使得F(i)全部合法。
样例1可行的解:
110
111
001
000
思路:
写出样例2的公式:
①F(0)=bF(2)
②F(1)=bF(0)
③F(2)=bF(1)
我们不难发现,如果我们设定了F(0)的值,就能够通过式子②能够得知F(1)的值,然后就能通过式子③得知F(2)的值,最后再回归式子①尝试当前设定的值是否合法了。
那么这里有一个环。
所以我们的解题关键就是找环。
那么我们O(n)就能够找到数组A中所有的环的信息,能够得知环的个数和每个环的长度。
那么我们再O(m)能够找到数组B中所有环的信息,能够得知环的个数和每个环的长度。
我们对于A数组中的一个环的话如果一个环中的任意一个点的价值我们能够设定出来,那么这一个环的所有点的值就都能够知道了。
然而这个能够设定的值,肯定是数组B中的一个值,而且我们已知都是环,那么数组B中的这个被选中设定的值也一定存在一个环,而且这个环的长度,一定是A长度环的因子长度。
那么我们O(n)找A数组的环,O(m)找B数组的环,然后对于A数组中长度为D的一个环,如果B数组中有一个环的长度为d,并且如果D%d==0.那么这个B数组的这个环的所有值,都可以作为A数组中这个环的值。那么对于A数组中的这个环来讲,答案数就多了d个。
过程统计每个环能够满足的答案的个数,然后累乘即可。
找环的信息不一定要用强连通来找,直接O(n)去找也行。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
using namespace std;
#define ll __int64
vector<int>mp[100505];
int a[150000];
int b[150000];
int stack[150000];
int color[155000];
int num[155000];
int num2[155000];
int dfn[155000];
int low[155000];
int vis[155000];
ll ans[155000];
map<int, ll >s;
int n,m;
int sig,cnt,tt,presig;
const ll MOD=1e9+7;
void Tarjan(int u)
{
vis[u]=1;
dfn[u]=low[u]=cnt++;
stack[++tt]=u;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(vis[v]==0)Tarjan(v);
if(vis[v]==1)low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
sig++;
do
{
color[stack[tt]]=sig;
vis[stack[tt]]=-1;
}
while(stack[tt--]!=u);
}
}
void Slove()
{
cnt=1,sig=0,tt=-1;
memset(num,0,sizeof(num));
memset(stack,0,sizeof(stack));
memset(color,0,sizeof(color));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(vis[i]==0)Tarjan(i);
}
for(int i=1;i<=n;i++)
{
num[color[i]]++;
}
presig=sig;
}
void Slove2()
{
cnt=1,sig=0,tt=-1;
memset(num2,0,sizeof(num2));
memset(stack,0,sizeof(stack));
memset(color,0,sizeof(color));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
{
if(vis[i]==0)Tarjan(i);
}
for(int i=1;i<=m;i++)
{
num2[color[i]]++;
}
for(int i=1;i<=m;i++)
{
s[num2[i]]+=num2[i];
}
}
int main()
{
int kase=0;
while(~scanf("%d%d",&n,&m))
{
s.clear();
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]++;
for(int i=1;i<=m;i++)scanf("%d",&b[i]),b[i]++;
for(int i=1;i<=n;i++)
{
mp[a[i]].push_back(i);
}
printf("Case #%d: ",++kase);
Slove();
for(int i=1;i<=m;i++)mp[i].clear();
for(int i=1;i<=m;i++)
{
mp[b[i]].push_back(i);
}
Slove2();
for(int i=1;i<=presig;i++)
{
for(int j=1;j<=sqrt(num[i]);j++)
{
if(num[i]%j==0)
{
ans[i]+=s[j];
if(num[i]/j!=j)
ans[i]+=s[num[i]/j];
}
}
}
ll output;
for(int i=1;i<=presig;i++)
{
if(i==1)output=ans[i];
else output*=ans[i];
output%=MOD;
}
printf("%I64d\n",output);
}
}