Function (HDU 6038)

Function

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


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

//题意:题目自己先看一边,不好解释,我讲组样例:

3 2
1 0 2
0 1

第一行的3表示a数组有3个元素,2表示b数组有2个元素,接下来两行分别是a、b数组。
根据题意可列方程:
F(0)=b(F(1))
F(1)=b(F(0))
F(2)=b(F(2))

打表:
F(0)       F(1)       F(2)
0            0            0
0            0            1
1            1            0
1            1            1

共有这么4种情况,输出4 。

这么讲应该懂了吧QAQ

//思路

F(0)=b(F(1))
F(1)=b(F(0))
F(2)=b(F(2))

从这里应该可以看出F(0)的值与F(1)是有关的,F(2)的值与它自己有关的,我们可以根据这个建个图:
0->1,1->0,2->2(a图)

还可以看出,b的值与它的下标也有关系,根据这个也再建个图:
0->0,1->1(b图)

我们分别计算出a、b里环的个数和每个环里元素的个数,设b中一个环是X,a中一个环是Y,若X里的元素个数等于Y或是Y的因子(即能被整除),那么a里这个环的情况数+=X的元素个数(因为Y中的一个顶点都可以是X里元素的一种,Y里知道一个顶点的值能推出Y里其他点的值)。那么总数sum=a里每个环的情况数的乘积。

这里算a里环的情况数的时候采用枚举,a里环一个个枚举,每个环去算的时候把b里的环都枚举判断一遍,非常暴力,竟然没TLE,神奇...


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;


const int MAX = 100000 + 100;
const int mod = 1000000007;


long long sum;
int n, m;
int a[MAX], b[MAX];
int vis[MAX];//图里的点是否被访问过


int amap[MAX];//a图
int ans;//a图里环的个数
int lena[MAX];//a里每个环里的点的个数


int bmap[MAX];//b图
int cnt;//b图里环的个数
int lenb[MAX];//b里每个环里的点的个数


//计算图里环的个数和每个环里点的个数
//标准的可以去看下tarjan算法,我这个是自己瞎写的,复杂度比较高...
int cul(int *map, int *len, int nn)
{
	int i, num;
	int lenth = 1;
	queue<int>q;
	memset(vis, 0, sizeof(vis));
	num = 0;
	q.push(0);
	vis[0] = 1;
	while (true)
	{
		while (!q.empty())
		{
			int now = q.front();
			q.pop();
			int next = map[now];
			if (!vis[next])
			{
				vis[next] = 1;
				q.push(next);
				lenth++;
			}
		}
		len[num] = lenth;
		num++;
		for (i = 0; i < nn; i++)
		{
			if (vis[i] == 0)
			{
				q.push(i);
				vis[i] = 1;
				lenth = 1;
				break;
			}
		}
		if (i == nn)
			break;
	}
	return num;
}


int main()
{
	int Case = 1;
	while (scanf("%d%d", &n, &m) != EOF)
	{
		memset(amap, 0, sizeof(amap));
		memset(bmap, 0, sizeof(bmap));


		//输入并建a图
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);
			amap[i] = a[i];
		}


		//输入并建b图
		for (int i = 0; i < m; i++)
		{
			scanf("%d", &b[i]);
			bmap[i] = b[i];
		}


		printf("Case #%d: ", Case++);


		//分别计算a、b图里环的个数和每个环里点的个数
		ans = cul(amap, lena, n);
		cnt = cul(bmap, lenb, m);


		sum = 1;
		long long kk;
		for (int i = 0; i < ans; i++)
		{
			kk = 0;


			//计算每个环可能的情况数
			for (int j = 0; j < cnt; j++)
			{
				if (lena[i] % lenb[j] == 0)
				{
					kk = (kk+ lenb[j]) % mod;
				}
			}


			//计算总情况数
			sum *= kk;
			sum = sum%mod;
		}


		sum = sum % mod;
		printf("%lld\n", sum);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值