比赛现场非常遗憾地没能成功AK的一题,当时最后一个小时已经想到做法,但是交给队友化简公式的时候我竟然非常sb的给错参数了=。=。。。尽管没AK也是冠军但是还是很遗憾啊,算了当给final攒rp吧!!

题意非常简单,给1、5、100、5000、10000五种硬币,每种数量无限,现在有总价值为n的钱,问如果全部兑换成硬币的话有多少种兑换方案?两个方案如果某一种硬币兑换数量不一样即可以视为不同方案。其中n<=10^18

如果n比较小的时候这显然可以用背包dp来处理,但是这里n非常大,所以应该利用硬币价值成倍数的特殊条件来设计更快的算法。

算法一:dp。这个是出题者教我的做法,时间复杂度为O(logn)

对于原问题,我们可以增加一个额外的限制,所有硬币按照价值从大到小依次使用。此时新问题的方案数必然与原问题方案数一样。先假设n是10000的倍数,此时由于所有硬币价值都是10000因子,所以很明显每一个10000的区间都是独立的子问题,即不可能有一个硬币跨越相邻两个10000区间。之后由于我们新增加的限制条件,每一个10000的区间使用的硬币价值都要小于等于上一个区间使用的硬币。于是可以使用dp预处理mat[i][j]表示上一个区间使用最小硬币是i,本区间使用的最小硬币是j,此时区间内放置方案数。之后一共拥有n/10000个这样的区间,我们可以使用矩阵快速加速计算。同理,我们可以把剩下部分提取出大小5000区间,继续使用矩阵乘法计算,等等。

方法二:暴力推导通項。这个是我自己YY出来的,公式推导比较麻烦,但是时间复杂度仅为O(1).

同样利用所以硬币价值都成倍数关系的特殊条件,如果我们先使用完价值为1的硬币,那么剩下的总价值必然需要是5的倍数。

首先考虑使用价值为1的硬币,令k1=n/5,那么余下价值可能是0,5,10,15...,n/5*5 , 此时每种情况出现方案数均为1,总方案数量设为tol1

之后考虑使用价值为5的硬币,那么余下价值也只可能是0,100,200,。。n/100*100, 此时对于剩余价值为100*i的情形,原先剩余价值已经小于它的方案必定不能取完之后剩余价值变成100*i,故使得这种情形出现的方案数可以用该通項表示  tol1-20i,此时的总方案数量也是可以计算的,设其为tol2。这里我们可以将通项设置A2i+B2方便后续计算。

之后考虑使用价值为100的硬币的时候,余下价值必然是0,5000,10000,。。n/5000*5000。对于剩余价值的为5000i的情形出现的方案数,我们依旧可以使用上诉方法计算第i項其通項为 tol2-∑(A2x+B2) ( 其中 x=0..50i-1),对∑x化简之后可以得到2次的通項A3*i^2+B2*i+C2,此时总方案数依旧可以计算。

最后考虑使用价值为5000的硬币的时候,同理我们可以化简出4次方级别的通項,此时新的总方案数就是原问题的答案,应为最后的剩余价值只有一种处理方法即用10000价值的硬币取尽它。

最后,在求解通項的时候将其表示成普通多项式的形式,会使得推导下一层通項的时候简单很多。

附代码:

方法一

 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12
13 #define eps 1e-9
14 #define N 100010
15 #define sqr(x) ((x)*(x))
16 #define Rep(i,n) for(int i = 0; i<n; i++)
17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
18 #define X first
19 #define Y second
20 #define mp(x,y) make_pair(x,y)
21
22 using namespace std;
23 typedef long long LL;
24 typedef pair<int,int> pii;
25
26 #define MOD 1000000007
27 const    int    mm[5] = {10000,5000,100,5,1};
28 LL        mat[5][5][5];
29 LL        dp[10010];
30
31
32 LL        cal(int L , int l ,int r ){
33     if ( mm[r] > L ) return 0;
34     memset( dp , 0 , sizeof(dp) );
35     dp[0] = 1;
36     for(int i = l; i<r; i++) {
37         for(int j = 0; j+mm[i] < L; j++){
38             dp[j+mm[i]] += dp[j];
39             dp[j+mm[i]] %= MOD;
40         }
41     }
42     LL    ret = 0;
43     for(int j = 0; j<L; j++) ret += dp[j];
44     return ret%MOD;
45 }
46
47 void    cheng( LL ret[][5] , LL A[][5] , LL B[][5] ){
48     static LL    C[5][5];
49     Rep(i,5) Rep(j,5){
50         C[i][j] = 0;
51         Rep(k,5) C[i][j] += A[i][k]*B[k][j]%MOD;
52         C[i][j] %= MOD;
53     }
54     Rep(i,5) Rep(j,5) ret[i][j] = C[i][j];
55 }
56
57 void    quick_sqr( LL ret[][5] , LL g[][5] , LL h ){
58     while ( h ) {
59         if ( h&1ll ) cheng( ret , ret , g );
60         cheng( g , g , g );
61         h>>=1;
62     }
63 }
64
65 LL        A[5][5],B[5][5];
66
67 int        main(){
68     Rep(i,5) Rep(j,5)
69         for(int k = j; k<5; k++) {
70             mat[i][j][k] = cal(mm[i],j,k);
71         }
72     int cas;
73     LL    n;
74     scanf("%d", &cas );
75     while ( cas -- ) {
76         cin >> n;
77         LL    m = n;
78         Rep(i,5) Rep(j,5) A[i][j] = i==j?1:0;
79         for(int k = 0; k<5; k++) {
80             Rep(i,5) Rep(j,5) B[i][j] = mat[k][i][j];
81             quick_sqr(A,B,n/mm[k]);
82             n %= mm[k];
83         }
84         LL    ans = 0;
85         Rep(j,5) ans = (ans + A[0][j] ) %MOD;
86         printf("%lld\n" , ans );
87     }
88     return 0;
89 }

方法二

 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12
13 #define eps 1e-9
14 #define N 100010
15 #define sqr(x) ((x)*(x))
16 #define Rep(i,n) for(int i = 0; i<n; i++)
17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
18 #define X first
19 #define Y second
20 #define mp(x,y) make_pair(x,y)
21
22 using namespace std;
23 typedef long long LL;
24 typedef pair<int,int> pii;
25
26 #define MOD 1000000007
27
28 LL        niyuan(LL g){
29     LL    ret = 1 , h = MOD-2;
30     while ( h ) {
31         if ( h&1ll ) ret = ret*g%MOD;
32         g = g*g%MOD;
33         h >>= 1;
34     }
35     return ret;
36 }
37
38 LL        getsum(int kind , LL K ){
39     K %= MOD;
40     if ( kind == 0 ) return (K+1)%MOD;
41     if ( kind == 1 )
42         return K*(K+1)%MOD*niyuan(2)%MOD;
43     if ( kind == 2 )
44         return K*(K+1)%MOD*(2*K+1)%MOD*niyuan(6)%MOD;
45     if ( kind == 3 )
46         return K*K%MOD*(K+1)%MOD*(K+1)%MOD*niyuan(4)%MOD;
47 }
48
49 LL        solve4( LL A , LL B, LL C , LL D , LL K ){
50     LL    tol = getsum(0,K)*D%MOD+getsum(1,K)*C%MOD+getsum(2,K)*B%MOD+getsum(3,K)*A%MOD;
51     tol %= MOD;
52     return tol;
53 }
54 LL        solve3( LL A , LL B , LL C , LL K ){
55     LL    tol = getsum(0,K)*C%MOD+getsum(1,K)*B%MOD+getsum(2,K)*A%MOD;
56     tol %= MOD;
57     LL    pA = 16*A%MOD*niyuan(6)%MOD ,
58         pB = ((2*B-2*A)%MOD+MOD)%MOD ,
59         pC = ((2*A%MOD*niyuan(6)%MOD-B+2*C)%MOD+MOD)%MOD;
60     return solve4(MOD-pA,MOD-pB,MOD-pC,tol,K/2);
61 }
62 LL        solve2( LL A , LL B , LL K ){
63     LL    tol = getsum(0,K)*B%MOD+getsum(1,K)*A%MOD;
64     tol %= MOD;
65     LL    pA = 25*50*A%MOD ,
66         pB = ((50*B-25*A)%MOD+MOD)%MOD;
67     return solve3(MOD-pA,MOD-pB,tol,K/50);
68 }
69 LL        solve1( LL K ){
70     return solve2( MOD-20 , (K+1)%MOD  , K/20 );
71 }
72
73 int        main(){
74     int    cas;
75     scanf("%d", &cas );
76     while ( cas -- ) {
77         LL    n;
78         cin >> n;
79         printf("%lld\n" , solve1(n/5) );
80     }
81     return 0;
82 }

转载于:https://www.cnblogs.com/lzqxh/archive/2013/05/13/3076417.html

【数学、dp】bigcoin 2013广东省赛E题相关推荐

  1. xdu1068暨2013陕西省赛C题题解

    xdu1068暨2013陕西省赛C题题解 题意 知道两个数列M和F,每次从M中选择一个人,和从F中选择的一个人配对,结果是Mi*Fj,请问所有配对情况中第k大的情况是多少. 笺释 先对M和F从小到大排 ...

  2. 数学建模之2016国赛A题程序(来源于cclplus)

    友情链接: (1)2016数学建模国赛A题程序(原创)作者cclplus https://blog.csdn.net/m0_37772174/article/details/80204533 也可以在 ...

  3. 【数学建模】2022亚太赛A题 结晶器熔炼结晶过程序列图像特征提取与建模分析

    2022亚太赛A题 1 前言 2 问题重述 3 问题一 3.1 数据处理 3.1.1 图像裁剪 3.1.2 提取红色部分 3.2 汉字提取 3.2.1 失败的例子 3.2.2 正确的例子 4 问题二 ...

  4. 数学建模篇---2022国赛C题(一)

    先从今年的国赛C题说起吧,第一次建模比赛还是很紧张的,和队友晚上五点就在等着啦 初步看一下三道题,作为知识储备不深的三位小白果断选择C题,数据分析题 国赛C题:先来看一下题 问题 1 对这些玻璃文物的 ...

  5. 【数学建模】2022小美赛C题 人类活动分类(Classify Human Activities)

    2022小美赛 1 前言 2 问题重述 3 问题解决思路 4 问题求解(原始模型) 4.1 特征提取 4.2 数据集划分 4.3 评价指标选择 4.4 模型的选择 4.5 各模型的性能表现 5 改进的 ...

  6. 数学建模篇---2022国赛C题(二)(全程python,完整论文和代码可取!)

    接着上回我们继续第三题 问题 3 对附件表单 3 中未知类别玻璃文物的化学成分进行分析,鉴别其所属类型,并对 分类结果的敏感性进行分析. 我们的分析: 基于问题二的分类模型,计算出每个待测样本点与簇中 ...

  7. 华为杯数学建模优秀论文_数学建模经典例题(2013年国赛A题与优秀论文)

    数学建模经典例题 (更多往期经典例题可点击文章最后相关推荐哦) 相关推荐 数学建模经典例题(2000年国赛B题与解题思路) 数学建模经典例题(2001年国赛A题与优秀论文) 数学建模经典例题(2001 ...

  8. (数学建模)2013年国赛B题-碎纸片复原python代码

    数字图像处理的期末大作业 成绩出来了,感觉一般般,做个记录 代码图片文件:数学建模2013年国赛B题碎纸片复原(纵切和横纵切两问)-统计分析文档类资源-CSDN下载 目录 第一问 碎纸片拼接--纵切 ...

  9. 蓝桥杯13-20届真题答案和解析(Java 大学 B 组)2013年省赛真题3_振兴中华

    蓝桥杯13-20届真题解析(Java 大学 B 组)2013年省赛真题3_振兴中华 一.振兴中华[填空] 1.题目描述 2.简要分析 3.代码实现(递归) 4.答案 一.振兴中华[填空] 1.题目描述 ...

最新文章

  1. 没有互联网,我不会写程序了
  2. 学姐百度实习面经(轻松拿offer)
  3. 链家信息python
  4. VoIP:难以抵挡的灰色诱惑
  5. postgre sql安装时忘记之前密码时如何处理。
  6. 论文赏析[NAACL19]基于DIORA的无监督隐式句法树归纳
  7. MVC5+EF6之EF CRUD
  8. Java并发包一览图
  9. 一文详解:中信银行java笔试题库
  10. c语言求三角形周长代码,C语言求三角形面积和周长
  11. [bhpyg] QQ互联接口 ,第三方帐号登录
  12. 可编程计数器/定时器8253和8254
  13. 基于视觉的扫地机器人导航系统(模块设计)
  14. 初次使用tshark小结
  15. PLSQL启动报错:Initialization error
  16. jenkins中的流水线( pipeline)的理解(未完)
  17. 小米平板一直android,小米平板下架,号称最好用的安卓平板也退出了市场
  18. 替换word中手动换行(软回车)为段落标记(硬回车)
  19. PTA-幂级数展开的部分和
  20. linux mysql5.7.36 离线安装使用全教程(含安装包)

热门文章

  1. 华为鸿蒙系统发展时间2021年,耗时八年打造国产系统,华为鸿蒙OS质疑声不断,它才是真正未来...
  2. 腐蚀rust高速箭怎么做不了_高速公路波形护栏板安装时的设置要求
  3. python将argv作为参数,Python当中的命令行参数sys.argv[]的使用方法
  4. 依存句法分析 oracle,spaCy 第三篇:依存分析
  5. 书籍折页是什么效果_Word的书籍折页是什么
  6. img 样式单和属性
  7. STM8单片机通过PWM触发ADC同步采样
  8. Tensorflow Auto-encoder + VAE 实战
  9. Pytorch:比较函数
  10. 运行时数据区——Java虚拟机栈