您的位置:首页 > 其它

hdu5564 Clarke and digits【数位dp+矩阵快速幂】

2018-01-04 21:28 295 查看

题目大意:

求长度在[l,r]之间的能被7整除且相邻数位之和不为k的正整数有多少个。 1≤l,r≤109

解题思路:

设f[x][i][j]表示第x位为j,模7余数为i的方案数,那么易得转移方程:f[x+1][(i∗10+k)%7][k]+=f[x][i][j]。

可以发现每一位的转移都是一样的,所以可以只记状态f[i][j],并把其压为f[i∗10+j]的一维状态,就可以按dp方程构造一个70*70的转移矩阵来快速幂转移了。

注意0不能计算在答案中很麻烦,所以初始时有

a[0][(i%7)∗10+i]=1,1≤i≤9;

但这样转移x轮只能得到长度为x+1的方案数(有前缀0的都为0),所以还要在转移矩阵中多开一层记录前缀和,详见代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

const int p=1e9+7;
struct matrix
{
int a[71][71];
inline friend matrix operator * (const matrix &A,const matrix &B)
{
matrix res;
memset(res.a,0,sizeof(res.a));
for(int i=0;i<=70;i++)
for(int k=0;k<=70;k++)
for(int j=0;j<=70;j++)
res.a[i][j]=(res.a[i][j]+1ll*A.a[i][k]*B.a[k][j]%p)%p;
return res;
}
inline friend matrix Pow(matrix A,int b)
{
matrix res;
memset(res.a,0,sizeof(res.a));
for(int i=0;i<70;i++)res.a[i][i]=1;
for(;b;b>>=1,A=A*A)
if(b&1)res=res*A;
return res;
}
}A,B,t;
int T,l,r,K,ans;

int main()
{
//freopen("lx.in","r",stdin);
T=getint();
while(T--)
{
memset(A.a,0,sizeof(A.a));
memset(B.a,0,sizeof(B.a));
memset(t.a,0,sizeof(t.a));
l=getint(),r=getint(),K=getint();
for(int i=0;i<7;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
{
if(k+j==K)continue;
int x=i*10+j,y=((i*10+k)%7)*10+k;
t.a[x][y]=1;
}
for(int i=0;i<=9;i++)t.a[i][70]=1;
t.a[70][70]=1;
for(int i=1;i<=9;i++)A.a[0][(i%7)*10+i]=1;
ans=0;
B=A*Pow(t,l-1);
ans=(ans-B.a[0][70]+p)%p;
B=A*Pow(t,r);
ans=(ans+B.a[0][70]+p)%p;
cout<<ans<<'\n';
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: