Clarke and digits
Time Limit: 5000/3000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 277 Accepted Submission(s): 176
Problem Description
Clarke is a patient with multiple personality disorder. One day, Clarke turned into a researcher, did a research on digits.
He wants to know the number of positive integers which have a length in and are divisible by and the sum of any adjacent digits can not be .
Input
The first line contains an integer , the number of the test cases.
Each test case contains three integers .
Output
Each test case print a line with a number, the answer modulo .
Sample Input
2 1 2 5 2 3 5
Sample Output
13 125
Hint:
At the first sample there are 13 number:
7,21,28,35,42,49,56,63,70,77,84,91,98
7
,
21
,
28
,
35
,
42
,
49
,
56
,
63
,
70
,
77
,
84
,
91
,
98
satisfied.
题意大概就是位数在l-r中能被整除7且任意相邻位数差不为k的数有多少个,答案对1e9+7取模。
解:
这也是一个一眼题(一眼咋做)。我们用 fi,j f i , j 表示末尾为 i i 且模7为的数有多少。
然后矩阵状态转移。
显然不能手推,用手推的都凉了,而且这个矩阵是不确定的,因为题目有一个输入 k k 。简单讲一下,状态矩阵的一般姿势:先把所有状态排成一排。然后开一个状态数平方的矩阵。如果状态 p1 p 1 可以转移到状态 p2 p 2 ,假设 p2 p 2 += α∗p1 α ∗ p 1 。那么我们在 A(p1,p2) A ( p 1 , p 2 ) 上加上一个 α α <script type="math/tex" id="MathJax-Element-163">α</script>。然后我们就可以做矩阵转移了。
然后由于这道题不好做初始状态,我们在状态中加一个表示没有放数,可以转移到放每个数。
贴波代码(矩阵快速幂越来越溜了):
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n=71,T,l,r,c;
long long const mod=1000000007;
struct lxy{
long long m[105][105];
lxy operator *(const lxy &q){
lxy C;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
C.m[i][j]=0;
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
{
if(m[i][k]==0) continue;
for(int j=1;j<=n;j++)
C.m[i][j]=(C.m[i][j]+m[i][k]*q.m[k][j])%mod;
}
return C;
}
}key,A;
lxy quick(lxy B,int x)
{
lxy C;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j) C.m[i][j]=1;
else C.m[i][j]=0;
}
while(x!=0)
{
if((x&1)==1) C=B*C;
B=B*B;
x=x>>1;
}
return C;
}
long long solv(int x)//A.m[1][a*7+1+b%7]表示末尾为a,模7为b的数的数量
{
if(x==0) return 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
key.m[i][j]=0;
for(int i=1;i<=n;i++)
A.m[1][i]=0;
A.m[1][71]=1;//71这一维表示前面没有放数
for(int i=1;i<=9;i++)//没有放过数可以下一位放任意数
key.m[71][i*7+1+i%7]++;
key.m[71][71]=1;//可以接着不放数
for(int i=0;i<=9;i++)
for(int j=0;j<=6;j++)
for(int k=0;k<=9;k++)//每个状态枚举下一位放什么
if(i+k!=c)//判断是否合法
key.m[i*7+1+j][k*7+1+(j*3+k)%7]++;
key=quick(key,x);
A=A*key;
long long ret=0;
for(int i=0;i<=9;i++)
ret=(ret+A.m[1][i*7+1])%mod;
return ret;
}
int main()
{
scanf("%d",&T);
while(T--)
{
long long ans=0;
scanf("%d%d%d",&l,&r,&c);
ans=(solv(r)-solv(l-1))%mod;
ans=(ans+mod)%mod;
printf("%lld\n",ans);
}
}