博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Count Numbers
阅读量:5213 次
发布时间:2019-06-14

本文共 3345 字,大约阅读时间需要 11 分钟。

Count Numbers

时间限制: 8 Sec  内存限制: 128 MB

题目描述

Now Alice wants to sum up all integers whose digit sum is exactly ab .
However we all know the number of this kind of integers are unlimited. So she decides to sum up all these numbers whose each digit is non-zero.
Since the answer could be large, she only needs the remainder when the answer divided by a given integer p.

 

输入

The input has several test cases and the first line contains the integer t (1 ≤ t ≤ 400) which is the number of test cases.
For each test case, a line consisting of three integers a, b (1 ≤ a, b ≤ 20) and p (2 ≤ p ≤ 109 ) describes the restriction of the digit sum and the given integer p.

 

输出

For each test case, output a line with the required answer.
Here we provide an explanation of the following sample output. All integers satisfying the restriction in the input are 4, 13, 31, 22, 121, 112, 211 and 1111. The sum of them all is 4 + 13 + 31 + 22 + 121 + 112 + 211 + 1111 = 1625 and that is exactly the sample output.

 

样例输入

52 1 10000003 1 10000002 2 10000003 3 100000010 1 1000000

 

样例输出

131471625877377935943

题意:求十进制下各个位上的数字和为n的数的总和。 分析:首先n很大,要用__int128来存,其次要能求出关于n的递推式。分析n=k的情况,我们尝试来构造出这些满足条件的数。如果这个数的最后一位为1,那么就需要求出所有k-1的答案数字,然后在其最后加上1,如果最后一位为2,那么就需要求出所有k-2的答案数字,然后在其最后加上2,。。。。。。。 一直可以分析到最后一位为9的情况。那么我们需要两个数组ans[i],cut[i],ans[i]代表n=i时的答案是多少,cut[i]代表n=i时满足数字和是i的数字有多少个。因此就可以推出递推公式:cut[i]=sum(cut[i-j]){1<=j<=9},ans[i]=sum(10*ans[i-j]+j*cut[i-j]){1<=j<=9}。 有了递推式就可以套矩阵快速幂了,这里要注意矩阵要开18*18的,这样方便转移状态。 还有要注意的就是矩阵最好写成int类型的,以防超时。(顺便mark一下加取模和乘取模的函数)。 最后一点就是矩阵乘法可以放弃以往的一行乘一列的写法,用一种新的写法,这样可以省下不少时间。
#include
//#define __int128 long longusing namespace std;long long p=1e9+7;int addmod(int a,int b) //加法取模 { return a+b>=p?a+b-p:a+b;}int mulmod(long long a,int b) //乘法取模 { return a*b%p;}struct Mat{ int v[18][18]; Mat() { memset(v, 0, sizeof(v)); } void init() { for (int i=0; i<18; i++) v[i][i]=(int)1; }};Mat operator *(Mat a,Mat b){ Mat c; for (int i=0; i<18; i++) { for (int j=0; j<18; j++) //换了一种写法,节省计算0的时间 if(a.v[i][j]) { for (int k=0; k<18; k++) if(b.v[j][k])c.v[i][k]=addmod(c.v[i][k],mulmod(a.v[i][j]%p,b.v[j][k]%p)); } } return c;}Mat qmod(Mat a,__int128 k){ Mat c; c.init(); while (k>0) { if (k&1) c=c*a; a=a*a; k>>=1; } return c;}int main(){ long long ans[15]= {
0},cut[15]= {
0}; cut[0]=1; for(int i=1; i<=9; i++) for(int j=1; j<=i; j++)ans[i]+=10*ans[i-j]+j*cut[i-j],cut[i]+=cut[i-j]; Mat a,b; for(int i=0; i<9; i++)a.v[0][i]=10; for(int i=9; i<18; i++)a.v[0][i]=i-8; for(int i=1; i<9; i++)a.v[i][i-1]=1; for(int i=9; i<18; i++)a.v[9][i]=1; for(int i=10; i<18; i++)a.v[i][i-1]=1; int t; scanf("%d",&t); while(t--) { long long aa,bb; scanf("%lld %lld %lld",&aa,&bb,&p); for(int i=0; i<9; i++)b.v[i][0]=ans[9-i]%p; for(int i=9; i<18; i++)b.v[i][0]=cut[18-i]%p; __int128 now=aa; for(int i=2; i<=bb; i++)now=now*(__int128)aa; if(now<=9) { printf("%lld\n",ans[now]%p); continue; } Mat c=qmod(a,now-9)*b; printf("%lld\n",c.v[0][0]); } return 0;}
View Code

 

转载于:https://www.cnblogs.com/tian-luo/p/9515011.html

你可能感兴趣的文章
IE11兼容IE8的设置
查看>>
windows server 2008 R2 怎么集成USB3.0驱动
查看>>
Foxmail:导入联系人
查看>>
在windows上安装ubuntu双系统
查看>>
JavaScript AJAX原生写法
查看>>
NodeJs实现WebSocket——express-ws
查看>>
NodeJS怎么实现WebSocket功能
查看>>
vue:axios二次封装,接口统一存放
查看>>
Js三大特性--封装、继承以及多态
查看>>
2019年8月2日07:51:10 马上要撤
查看>>
vue中router与route的区别
查看>>
js 时间对象方法
查看>>
网络请求返回HTTP状态码(404,400,500)
查看>>
Spring的JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate
查看>>
Mac下使用crontab来实现定时任务
查看>>
303. Range Sum Query - Immutable
查看>>
迪杰斯特拉算法---单源点最短路径
查看>>
【python】TCP/IP编程
查看>>
JVM 类型的生命周期学习
查看>>
图片加载失败显示默认图片占位符
查看>>