2017 Multi-University Training Contest
来源:互联网 发布:苹果mac 怎样更新系统 编辑:程序博客网 时间:2024/06/05 04:06
Function
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1354 Accepted Submission(s): 624
Define that the domain of function
Please calculate the quantity of different functions
Two functions are different if and only if there exists at least one integer from
The answer may be too large, so please output it in modulo
For each case:
The first line contains two numbers
The second line contains
The third line contains
It is guaranteed that
3 21 0 20 13 42 0 10 2 3 1
Case #1: 4Case #2: 4
题目说函数f,它的定义域取自数组b,然后看是否能够满足对应的关系使得 f(i) = b(fa[i])
说一下第一组测试数据是怎么来的:
按照上面树的顺序:
取 f(0)=0 , f(1) = 0, f(2) = 0;
bf(a[0]) = bf(1) = 0 = f(0) 成立
bf(a[1]) = bf(0) = 0 = f(1) 成立
bf(a[2]) = bf(2) = 0 = f(2) 成立
则 0 0 0 就是一组符合要求的解。按照上面的方法可以找到其他的解:
分别是 0 0 1
1 1 0
1 1 1
所以答案是4:
我们还可以分析题目中给出的第二组测试数据:
f(0) = bf(a[0]) = bf(2)
f(1) = bf(a[1]) = bf(0)
f(2) = bf(a[2]) = bf(1)
从式子中可以看出,如果现在从b数组中取一个值给f(0),则就可以推出f(1),当推出f(1)后,就可以推出f(2),
如果此时f(2)的值代进第一个式子,能够推得f(0),说明最初对f(1)的假设是正确的,否则这组解就是错误的。
因此假如现在已经知道f(i)的值可以满足一个循环节。
知道f(i) 就能知道 f(a[i]) ,知道f(a[i]),就能知道f(aa[i]),然后就能知道f(aaa[i]),因此一直这样下去肯定会再
回到f(i)。
f(i) -> f(a[i]) -> f(aa[i]) -> f(aaa[i]) - > ...... f(aa...aa[i]) = f(i) ,这样构成一个环,
则找数组a中的环的方法就是,确定 i ,a[i] ,aa[i]往前翻找,直到找到环了为止,假设环的长度为len.
即 i ,a[i] ,aa[i] ,aaa[i] , ...... ,aa...aa[i] , 最后aa,,,aa[i] = i,最后a有len个,则环的长度就是len.
对于一个len长度循环节中的f(i),我们有如下推导
f(i) = bf(a[i])
因为f(a[i]) = bf(a[a[i]]) 简便记录:变成 bf(aa[i])
带入上式
f(i) = bf(a[i]) = bbf(aa[i])
同样的道理往下推导:
f(i) = bf(a[i]) = bbf(aa[i]) = bbbf(aaa[i]) = bb...bbf(aa..aa[i])
因为f(i)所在的环的循环节的长度为len,则经过len个aa,,aa[i]会回到 i ,则最后 f(aa...aa[i]) = f(i),
同样最后b的长度也是len,我们知道f(i)无非就是b中的一个数,假如这个数是num
则bb,,,bbf(i)倒着推导回去 num,b[num],bb[num],....,bb..bb[num]
可以看出b数组中也对应着一些环,对于b,只要其循环节的长度是len的因子的话,这个循环节
中的所有数字,都能够打通这个长度为len的a中的环。不信的话,可以举例子证明这个结论:
假如a中一个环的长度为6.
f(i) = bbbbbbf(i) 6的因子为1,2,3,6
(1)假如b循环节的长度为1,其值为x
f(i) = x;
从后往前推导:
.,x,x,x,x,x,x,x
则b环中的一个元素x可以打通长度为6的a环。
(2)假如b循环节的长度为2,其值为x,y,x,y,x,y........
f(i) = x
往前推
x,y,x,y,x,y,x 元素x成功打通长度为6的a环
f(i) = y 从后往前推导
y,x,y,x,y,x,y 元素y成功打通长度为6的a环
则,b循环节长度为2,循环元素为x,y。这两个元素都能打通长度为6的a环。方案数就是2种
(3)假如b循环节长度为3,其值为x,y,z,循环是x->y->z->x
f(i) = x;
.x,z,y,x,z,y,x 元素x成功打通长度为6的a环
f(i) = y
y,x,z,y,x,z,y 元素y成功打通长度为6的a环
f(i) = z
z,y,x,z,y,x,z 元素z成功打通长度为6的a环。
则b循环节中的循环元素x,y,z都能打通长度为6的a环,那么方案数就是3种
(4)b循环节长度为6的情况,按上面方法推导吧。好累,就不推了,到这一步应该就明白了。
从上可以看出,b环种的数都是我设的,就用未知数表示,推理一下过程,可以看出,根a环和b环中的具体数字是没有
关系的,仅仅与他们的长度有关系。
因此才得到这样的结论:如果a中有长度为lena的循环节,b中存在lenb长度的循环节,如果lena%lenb==0
,则lenb中的所有元素的个数就是lenb,这些元素都能打通a环,a环,其方案数就是lenb种。
因此题目关键就是找环了。
下面是AC代码:
#include <iostream>#include <stdio.h>#include <string.h>#include <vector>using namespace std;typedef long long LL;const int maxn = 100010;const int mod = 1e9+7;int a[maxn]; ///放置序列aint b[maxn]; ///放置序列bint A[maxn]; ///A[i]代表序列a中循环节长度为i的环出没出现过int B[maxn]; ///B[i]代表序列b中循环节长度为i的环出没出现过int visa[maxn]; ///标记序列a中已经成环的那些数int visb[maxn]; ///标记序列b中已经成环的那些数int n,m;int main(){ int Case=0; while(~scanf("%d%d",&n,&m)) { memset(visa,0,sizeof(visa)); memset(visb,0,sizeof(visb)); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); vector<int>va; ///将序列a中各个环的长度,存放到容器中,每个长度只放置一次 vector<int>vb; ///将序列b中各个环的长度,存放到容器中,每个长度只放置一次 for(int i = 0; i < n; i++) scanf("%d",&a[i]); for(int j = 0; j < m; j++) scanf("%d",&b[j]); for(int i = 0; i < n; i++) { if(!visa[i]) ///i这个位置上的数不在任何环总 { int pos = i; int len = 0; while(!visa[pos]) { len++; visa[pos] = 1; pos = a[pos]; } if(A[len]==0) va.push_back(len); A[len]++; } } for(int i = 0; i < m; i++) { if(!visb[i]) { int pos = i; int len = 0; while(!visb[pos]) { len++; visb[pos] = 1; pos = b[pos]; } if(B[len]==0) vb.push_back(len); B[len]++; } } long long ans = 1; for(int i = 0; i < va.size(); i++) { int lena = va[i]; int temp = 0; for(int j = 0; j < vb.size(); j++) { int lenb = vb[j]; if(lena%lenb==0) { temp = (temp + (LL)(lenb*B[lenb]))%mod; } } for(int k = 1; k <= A[lena]; k++) ans = (ans*temp)%mod; } printf("Case #%d: %lld\n",++Case,ans); } return 0;}
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- #2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- #2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- ubuntu下环境变量详解 bashrc, profile, environment
- 2017 CCPC Partial Sum 前缀和
- 最大整数——解题报告
- STL 全排列(123,132......)
- jdbc基本知识(一)
- 2017 Multi-University Training Contest
- 同步函数解决线程安全
- Android开发之OnSaveInstanceState和onRestoreInstance详解
- python_爬虫今日头条
- 编程实战
- jenkins+SonarQube
- Servicemix配置文件的配置
- 方块消除游戏(完美世界2017秋招真题)
- Oracle笔记简单查询、限定查询、数据的排序