[COCI 2013/2014 ROUND 3] parovi

分析:简单的数位统计
    f[i][j]表示第i位为j的方案数,显然f数组是满足区间减法的,即[1,B]的f的值减去[1,A-1]的f的值便是[A,B]的f数组的值,我们的得到了f数组后就很好解决了:
    只需枚举位数i和数对的第i位,j和k:ans+=abs(j-k)*f[i][j]*f[i][k]

下面便是代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define maxlen 50010
#define Mod 1000000007
#define LL long long
using namespace std;

char A[maxlen],B[maxlen];
int lenr,lenl,len,L[maxlen],R[maxlen];
LL f[maxlen][10],g[maxlen],ten[maxlen],ans;

void Calc()
{
	ten[0]=1;
	for (int i=1;i<=maxlen;i++) ten[i]=(ten[i-1]*10)%Mod;
	LL r=0;
	lenr=strlen(B+1);
	for (int i=1;i<=lenr;i++) R[i]=B[lenr-i+1]-'0';
	g[lenr+1]=0;
	for (int i=lenr;i;i--) g[i]=(g[i+1]*10+R[i])%Mod;
	for (int i=1;i<=lenr;i++)
	{
		for (int j=0;j<=9;j++)
		{
			f[i][j]=(g[i+1]*ten[i-1])%Mod;
			if (j<R[i]) f[i][j]=(f[i][j]+ten[i-1])%Mod;
			else if (j==R[i]) f[i][j]=(f[i][j]+r+1)%Mod;
		}
		r=(r+R[i]*ten[i-1])%Mod;
	}
	lenl=strlen(A+1);
	for (int i=1;i<=lenl;i++) L[i]=A[lenl-i+1]-'0';
	L[1]--;
	for (int i=1;i<=lenl;i++) if (L[i]<0){L[i]+=10;L[i+1]--;}
	while (lenl>1 && !L[lenl]) lenl--;
	lenl=lenr;
	memset(g,0,sizeof g);
	for (int i=lenl;i;i--) g[i]=(g[i+1]*10+L[i])%Mod;
	r=0;
	for (int i=1;i<=lenl;i++)
	{
		for (int j=0;j<=9;j++)
		{
			f[i][j]=(f[i][j]-g[i+1]*ten[i-1]+Mod)%Mod;
			if (j<L[i]) f[i][j]=(f[i][j]-ten[i-1]+Mod)%Mod;
			else if (j==L[i]) f[i][j]=(f[i][j]-r-1+Mod)%Mod;
		}
		r=(r+L[i]*ten[i-1])%Mod;
	}
	len=max(lenr,lenl);
	ans=0;
	for (int i=1;i<=len;i++)
		for (int j=0;j<=9;j++)
			for (int k=0;k<=9;k++) ans=(ans+f[i][j]*f[i][k]*abs(j-k))%Mod;
}

int main()
{
	scanf("%s%s",A+1,B+1);
	Calc();
	cout<<ans<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值