您的位置:首页 > 其它

hdu 5564 Clarke and digits (dp+矩阵加速)

2015-11-16 13:20 549 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5564

题意:

问题描述
克拉克是一名人格分裂患者。某一天,克拉克变成了一个研究人员,在研究数字。
他想知道在所有长度在[l, r][l,r]之间的能被77整除且相邻数位之和不为kk的正整数有多少个。


输入描述
第一行一个整数T(1 \le T \le 5)T(1≤T≤5),表示数据的组数。
每组数据只有一行三个整数l, r, k(1 \le l \le r \le 10^9, 0 \le k \le 18)l,r,k(1≤l≤r≤10​9​​,0≤k≤18)。


输出描述
每组数据输出一行一个数,表示答案。由于答案太大,你只需对10^9+710​9​​+7取模即可。


输入样例
2
1 2 5
2 3 5


输出样例
13
125


Hint
第一个样例有13个数满足,分别是:7,21,28,35,42,49,56,63,70,77,84,91,987,21,28,35,42,49,56,63,70,77,84,91,98


分析:
定义dp[i][j][k]表示位数为i,当前数%7的值而且以k结尾的方案数。
那么有:       
for(int i=1;i<r;i++)
for(int j=0;j<7;j++)
for(int k=0;k<10;k++)
for(int x=0;x<10;x++) if(k+x!=K)
dp[i+1][(j*10+x)%7][x]+=dp[i][j][k];
但是r<=1e9,很大。不能直接递推,需要矩阵快速幂来加速递推。
首先建状态转移图(初始矩阵),mat[s1][s2]表示从状态s1到状态s2的方案数,当前数%7的值为i且以j结尾,s1=i*10+j,添加一个数x,i变为i'
,i'=(i*10+x)%7,j变为j',j'=x,那么状态s2=i'*10+j'。
然后需要多出一列来算累加和。
最后用快速幂直接求解。

代码:
#include <bits/stdc++.h>
using namespace std;

const int maxn = 72;
const int mod = 1e9+7;
struct Matrix
{
int mat[maxn][maxn];
Matrix()
{memset(mat,0,sizeof(mat));}
friend Matrix operator *(const Matrix &A,const Matrix &B);
friend Matrix operator ^(Matrix A,int n);
};

Matrix operator *(const Matrix &A,const Matrix &B) //mul
{
Matrix ret;
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
for(int k=0;k<maxn;k++)
(ret.mat[i][j]+=1ll*A.mat[i][k]*B.mat[k][j]%mod)%=mod;
return ret;
}
Matrix operator ^(Matrix A,int n)  //pow
{
Matrix ret;
for(int i=0;i<maxn;i++)
ret.mat[i][i]=1;
for(;n;n>>=1,A=A*A) if(n&1)
ret=ret*A;
return ret;
}
inline int Statu(int i,int j)
{
return i*10+j;
}
int main()
{
int nCase,i,j,L,R,K;
scanf("%d",&nCase);
while(nCase--)
{
scanf("%d%d%d",&L,&R,&K);
Matrix A,B;
for(i=0;i<7;i++)
for(j=0;j<10;j++)
for(int x=0;x<10;x++) if(j+x!=K)
B.mat[Statu(i,j)][Statu((i*10+x)%7,x)]++;
for(i=0;i<10;i++)
B.mat[Statu(0,i)][maxn-1]++;
B.mat[maxn-1][maxn-1]=1;
for(i=1;i<10;i++)
A.mat[0][Statu(i%7,i)]++;
Matrix ret1=A*(B^R);
Matrix ret2=A*(B^(L-1));
int res=ret1.mat[0][maxn-1]-ret2.mat[0][maxn-1];
while(res<0)	res+=mod;
while(res>=mod)	res-=mod;
printf("%d\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp