• 2017ACM暑期多校联合训练


    题目链接

    Problem Description
    You are given a permutation a from 0 to n−1 and a permutation b from 0 to m−1.

    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.

    Input
    The input contains multiple test cases.

    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.

    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

    题意:
    有两个,数组a是[0~n-1]的排列,数组b是[0~m-1]的排列。现在定义f(i)=b[f(a[i])];

    • 问f(i)有多少种取值,使得表达式f(i)=b[f(a[i])]全部合法。

    分析:
    以第一个样例 a={1,0,2} b={0,1}为例:

    那么f(0)=b[f(1)] f(1)=b[f(0)] f(2)=b[f(2)]

    这里有两个环分别为 f(0)->f(1) 和f(2)

    所以我们的任务就是在b中找环,该环的长度必须为a中环的长度的约数。

    为什么必须的是约数呢?
    因为如果b的环的长度是a的环的长度的约数的话,那也就意味着用b这个环也能构成a这个环,只不过是多循环了几次而已。

    然后找到a中所有环的方案数,累乘便是答案。

    为什么要累乘呢?我最开始一直以为要累加。

    这个就用到了排列组合的思想,因为肯定要f(i)肯定要满足所有的数,而a中的每个环都相当于从a中取出几个数的方案数,所以总共的方案数应该累乘。

    #include<iostream>
    #include<stdio.h>
    #include<vector>
    #include<string.h>
    using namespace std;
    const int max_n=100010;
    const int mod=1e9+7;
    int n,m;
    int a[max_n],b[max_n],len_b[max_n];
    bool vis[max_n];
    vector <int>A,fac[max_n];
    
    ///构建环,并返回环的大小
    int dfs(int N,int *c)
    {
        if(vis[N])
            return 0;
        vis[N]=1;
        return dfs(c[N],c)+1;
    }
    
    
    void get_fac()
    {
        for(int i=1; i<=100000; i++)///fac[j]里面保存的是长度为j的环的因子
        {
            for(int j=i; j<=100000; j+=i)
                fac[j].push_back(i);
        }
    }
    
    int main()
    {
        int Case=0;
        get_fac();
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=0; i<n; i++)
                scanf("%d",&a[i]);
            for(int i=0; i<m; i++)
                scanf("%d",&b[i]);
            A.clear();
            memset(vis,0,sizeof(vis));
            for(int i=0; i<n; i++)
            {
                if(vis[i]) continue;
                A.push_back(dfs(i,a));///a数组中环的长度,重复的长度也是保存的
            }
            memset(vis,0,sizeof(vis));
            memset(len_b,0,sizeof(len_b));
            for(int i=0; i<m; i++)
            {
                if(vis[i]) continue;
                len_b[dfs(i,b)]++;///b数组中长度为dfs(i,b)的环的个数
            }
            long long int ans=1;
            for(int i=0,L=A.size(); i<L; i++)
            {
                int la=A[i];///取出a中的一个长度为la的环
                long long res=0;
                for(int j=0,ll=fac[la].size(); j<ll; j++)
                {
                    int lb=fac[la][j];///lb是长度为la的环的一个因子
                    res=(res+(long long )lb*len_b[lb])%mod;///因子个数乘以环的个数就是一功德方案数
                }
                ans=ans*res%mod;
            }
            printf("Case #%d: %lld
    ",++Case,ans);
    
        }
    }
    
  • 相关阅读:
    Linux IO接口 监控 (iostat)
    linux 防火墙 命令
    _CommandPtr 添加参数 0xC0000005: Access violation writing location 0xcccccccc 错误
    Visual Studio自动关闭
    Linux vsftpd 安装 配置
    linux 挂载外部存储设备 (mount)
    myeclipse 9.0 激活 for win7 redhat mac 亲测
    英文操作系统 Myeclipse Console 乱码问题
    Linux 基本操作命令
    linux 查看系统相关 命令
  • 原文地址:https://www.cnblogs.com/cmmdc/p/7241354.html
Copyright © 2020-2023  润新知