2017 多校 Function(置换群

传送门

Function

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


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 from  0  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 2 1 0 2 0 1 3 4 2 0 1 0 2 3 1
 

Sample Output
  
  
Case #1: 4 Case #2: 4
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   6044  6043  6042  6041  6040 
 

题目大意:

给你一个数组A,和一个数组B,数组A是【0~n-1】的排咧,数组B是【0~m-1】的排列。

现在定义F(i)=bF(ai);

问有多少种取值,使得F(i)全部合法。


写出样例2的公式:


①F(0)=bF(2)

②F(1)=bF(0)

③F(2)=bF(1)


设想一下,这个题仔细想想有映射的关系,如果定F(i)中的i一定会有对应的b 也就是说确定一个值可以确定整个值。

多往b里推几下,会发现最终会有F(i)=bbbbbbb(i) 这样递归可以得到最终的循环节 也就是一个环。

预处理A,得到A 循环节个数和 形成的循环节。同样预处理B。

如果在A循环节的基础上,B里的一定是A循环节的因子才能完成A这个循环。

对于A数组中长度为D的一个环,如果B数组中有一个环的长度为d,并且如果D%d==0.那么这个B数组的这个环的所有值,都可以作为A数组中这个环的值。那么对于A数组中的这个环来讲,答案数就多了d个。

最终的答案就是每个循环节累乘的结果

//china no.1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;

#define pi acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,1,-1,-1,1};
const int dy[]={0,1,0,-1,-1,1,-1,1};
const int maxn=1e3+1e2;
const int maxx=1e5+1e2;
const double EPS=1e-7;
const LL MOD=1e9+7;
#define mod(x) ((x)%MOD);
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");


vector<int>G[maxx];
stack<int>S;
map<int,LL>mp;
int vis[maxx],dfn[maxx],low[maxx],bel[maxx],num[maxx],res,
a[maxx],b[maxx],num1[maxx];
int cont=1,n,m;
LL ans[maxx];
void dfs(int x)
{
    dfn[x]=low[x]=cont++;
    S.push(x);vis[x]=1;
    int len=G[x].size();
    for(int i=0; i<len; i++)
        if(!vis[G[x][i]])
        {
            dfs(G[x][i]);
            low[x]=min(low[x],low[G[x][i]]);
        }
        else if(vis[G[x][i]]==1)
            low[x]=min(low[x],dfn[G[x][i]]);
    if(dfn[x]==low[x])
    {
        res++;
        while(1)
        {
            int t=S.top();
            S.pop();
            vis[t]=2;  //访问完成
            bel[t]=res;
            if(x==t)break;
        }
    }
}
void init()
{
    me(dfn,0);me(vis,0);me(low,0);me(bel,0);me(a,0);me(b,0);
    me(num1,0);mp.clear();me(num,0);me(ans,0);
    res=0;cont=1;
}
void INIT()
{
    me(dfn,0);me(vis,0);me(low,0);me(bel,0);me(num,0);
    res=0;cont=1;
}

inline int Scan()
{
    int Res=0,ch,Flag=0;
    if((ch=getchar())=='-')Flag=1;
    else if(ch>='0' && ch<='9')Res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')Res=Res*10+ch-'0';
    return Flag ? -Res : Res;
}
int cas=1;
int main()
{
    //freopen("1006.in", "r", stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]++;
            G[a[i]].push_back(i);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&b[i]);
            b[i]++;
        }
        for(int i=1;i<=n;i++)
            if(!vis[i]) dfs(i);
        for(int i=1;i<=n;i++)
            num1[bel[i]]++;
        int val=res;
        for(int i=1;i<=n;i++)
            G[i].clear();
        INIT();
        for(int i=1;i<=m;i++)
            G[b[i]].push_back(i);
        for(int i=1;i<=m;i++)
            if(!vis[i]) dfs(i);
        for(int i=1;i<=m;i++)
            num[bel[i]]++;
        for(int i=1;i<=m;i++)
            mp[num[i]]+=num[i];
        for(int i=1;i<=m;i++)
            G[i].clear();
        for(int i=1;i<=val;i++)
            for(int j=1;j<=sqrt(num1[i]);j++)
        {
            if(num1[i]%j==0)
            {
                ans[i]+=mp[j];
                if(num1[i]/j!=j)
                    ans[i]+=mp[num1[i]/j];
            }
        }
        LL out;
        for(int i=1;i<=val;i++)
        {
            if(i==1) out=ans[i]%MOD;
            else
            {
                out*=ans[i];
                out%=MOD;
            }
        }
        printf("Case #%d: %I64d\n",cas++,out);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值