您的位置:首页 > 其它

HDU 4507 吉哥系列故事——恨7不成妻[数位dp]

2017-09-28 07:51 387 查看
首先计算和7有关的数的个数很简单

然后是算这些数的平方和

struct P{LL cnt,sum,tot;}dp[20][10][10];
/*
dp[pos][sum][mod]表示枚举到第pos位时,(pos之前的数位和%7)=sum,(pos之前的数%7)=mod
如pos=4时,已经枚举了前3位:345
sum=(3+4+5)%7=5,mod=(345)%7=2

然后可以满足当前这个状态的个数为cnt
这些数的和为sum
平方和为tot
*/


当前枚举位为i,pow[pos]=10^(pos-1),则:

cnt+=next.cnt;
//个数直接加
sum+=next.sum+i*pow[pos]*next.cnt;
//第pos位为i对sum的贡献为i*pow[pos]*next.cnt(应该很显然吧)
tot+=next.tot+((2*pow[pos]*i)*next.sum)+next.cnt*pow[pos]*pow[pos]*i*i;
//假设已经得到了整个数num,令a+b=num,其中 a=已经确定的数,b=num-a
//num^2=(a+b)^2=a^2+2*a*b+b^2
//就可以把num对tot的贡献分开统计,a直接算,b继续dfs


数比较大要开long long,有很多mod

#include<cstdio>
#include<cstring>
#define LL long long
#define MOD 1000000007
using namespace std;

inline LL read()
{
LL a=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){a=a*10ll+c-'0';c=getchar();}
return a*f;
}

struct P{LL cnt,sum,tot;}dp[20][10][10];
int n;
int a[20];
LL pow[20];

void init()
{
memset(dp,-1,sizeof(dp));
pow[1]=1;
for(int i=2;i<=20;++i)
pow[i]=pow[i-1]*10ll%MOD;
}

P dfs(int pos,int sum,int mod,int pre)
{
if(pos==0)
{
P tmp={sum&&mod,0,0};
return tmp;
}
if(!pre&&dp[pos][sum][mod].cnt!=-1) return dp[pos][sum][mod];
P tmp={0},ans={0};
int up=pre?a[pos]:9;
for(int i=0;i<=up;++i)
if(i!=7)
{
tmp=dfs(pos-1,(sum+i)%7,(mod*10+i)%7,i==up&&pre);
ans.cnt=(ans.cnt+tmp.cnt)%MOD;
ans.sum=((ans.sum+tmp.sum)%MOD+i*pow[pos]%MOD*tmp.cnt%MOD)%MOD;
ans.tot=(ans.tot+(tmp.tot+((2*pow[pos]*i)%MOD*tmp.sum)%MOD)%MOD)%MOD;
ans.tot=(ans.tot+(tmp.cnt*pow[pos])%MOD*pow[pos]%MOD*i*i%MOD)%MOD;
}
if(!pre) dp[pos][sum][mod]=ans;
return ans;
}

LL solve(LL x)
{
LL n=x;int pos=0;
while(n) a[++pos]=n%10,n/=10;
P ans=dfs(pos,0,0,1);
return ans.tot;
}

int main()
{
init();
int i;LL test=read();
while(test--)
{
LL l=read(),r=read();
LL ans=solve(r)-solve(l-1);
ans=(ans+MOD)%MOD;
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: