标签:
MODSUM(modsum.pas/c/cpp)
【问题描述】
在本题中,你得到了一个含有n个参数的函数f:
f(x1,…,x2)=(((x1+x2+…+xn)4+2*(x1+x2+…+xn)2) mod 5)+1
为了避免出现争议,函数f只接受整数参数。你的任务是计算f的所有函数值的和,每个参数xi是从vi到wi之间的整数。也就是说,你需要计算
例如,如果n=3,v1=2,w1=3.v2=10,w2=12,v3=17,w3=17,那么这个结果应该是19。因为f(2,10,17) = 4, f(2,11,17) = 1, f(2,12,17) = 4, f(3,10,17) = 1,f(3,11,17) = 4 and f(3,12,17) = 5。
重要提示:你可以认为这个结果是总小于1,000,000的。
【输入】
你的程序必须从标准输入中读取数据。输入包含一个数n(1≤n≤1000),跟在n后面有n对数,vi和wi,你可以认为vi≤wi,vi和wi都是0~100之间的整数。比如上面这个例子,输入是:
3 2 3 10 12 17 17
【输出】
你的程序必须从标准输出中输出。输出计算出的和。比如上面这个例子,输出则是:
19
【数据范围】
你的程序将会被5套测试数据测试:
1. (5分)n≤6;
2. (5分)n≤20;
3. (5分)n≤100;
4. (5分)n≤200;
5. (5分)n≤1000.
【题目分析】
看到本题,我们第一个反应到的算法应该就是搜索算法,深度优先搜索解答树,即枚举每个数从vi到wi的值,逐个计算函数值,最后累加。但是分析一下极端情况我们会发现,枚举量会达到1011000,这个枚举量是难以接受的,但是题目中给了我们一个重要信息——最后的值不会超过1,000,000,每一个函数值最小为1,最大为5,和不超过1,000,000,也就代表着最多枚举量不会超过1,000,000。这样我们使用DFS搜索解答树完全是可行的。但是由于循环的层数不固定,所以我们通过递归的方式来变相的达到循环的效果。
比如题目中所给的例子的解答树是:
但是从DFS可以看出,它计算了很多重复的值,浪费了很多的时间。那么我们可以考虑采用BFS的思想,逐层进行DP的方式进行处理。
在此之前,我们先计算出一个表格,用来计算当Σxi%5分别等于 0,1,2,3,4时f(x1,…,xn)的取值,方便后面的计算。
Σxi%5 |
f(x1,…,xn) |
0 |
1 |
1 |
4 |
2 |
5 |
3 |
5 |
4 |
4 |
那么,我们设f[i][y]表示前i个数里面,Σxi%5=y的种类数。那么状态转移方程为:
(其中,c[i][z]表示第i个数所在的范围vi到wi之间除以5余z的数的数量。边界f[0][0]=1)
例如:f[4][0]=f[3][0]*c[4][0]+f[3][1]*c[4][4]+f[3][2]*c[4][3]+f[3][3]*c[4][2]+f[3][4]*c[4][1]。
样例分析:前四个数的和除以5余0的可能有:前三个数的和余0的数再加上第四个数的范围内余0的数,最终和余数仍为0(种类用乘法);前三个数的和余1的数再加上第四个数的范围内余4的数,最终和余数仍为0(种类用乘法)…以此类推。
而最后,我们把f[n][0]~f[n][4]中的数分别和上表的数相乘,再相加即为最终答案。
【程序源代码】
1. 递归计算代码:
2. 动态规划代码:
欢迎鄙视。
标签:
原文地址:http://www.cnblogs.com/jerryxie/p/4780693.html