题解:P8245 [COCI2013-2014#3] PAROVI

题意

定义两个整数 A,B 之间的距离为这两个整数所有对应位上的数的差的绝对值之和,记为 dist(A,B)。特别地,如果 A,B 两数的位数不相同,则在位数较小的数前补足前导 0

现在,给定两个整数 L,R,请你求出所有在区间 [L,R] 内的整数对的距离和。请对 109+7 取模

分析

考虑记录在每一个数位上每个数出现了多少次。

cnti,j 表示第 i 位上数码 j 出现了多少次。

这样我们就可以枚举数码 j 以统计答案,答案即为:

2i=1len(R)j=09k=j+19(kj)×cnti,j×cnti,k

我们只需要解决 cnt 的计数问题就行了。

首先将问题转化为求 [0,L1][0,R] 各数码在每一位出现的次数,二者相减即是答案区间 [L,R]

上面所求的可以使用数位 dp 解决。

时间复杂度 O(logR)

Code

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
int64_t ksm(int64_t x, int l)
{
int64_t ret=1;
for(;l;l>>=1, x=x*x%mod)
if(l&1) ret=ret*x%mod;
return ret;
}
int64_t cnt[50004][10];
int64_t tag[50004];
int64_t calc(const string &s, int p, int op)
{
if(p<0) return 1;
int64_t mx=s[p]^48;
int64_t w=ksm(10, p);
if(p) tag[p-1]=((tag[p-1]+op*ksm(10, p-1)*mx)%mod+mod)%mod;
for(int i=0;i<mx;i++) cnt[p][i]=((cnt[p][i]+w*op)%mod+mod)%mod;
int64_t ret=mx*w%mod;
int64_t tmp=calc(s, p-1, op);
cnt[p][mx]=((cnt[p][mx]+tmp*op)%mod+mod)%mod;
return (ret+tmp)%mod;
}
string a, b;
void reduce(string &s)
{
reverse(s.begin(), s.end());
for(auto &c:s)
{
if(c^48) {c--; break;}
c='9';
}
if(s.back()=='0') s.pop_back();
reverse(s.begin(), s.end());
}
int main()
{
cin>>a>>b;
reduce(a);
reverse(b.begin(), b.end());
reverse(a.begin(), a.end());
while(a.size()<b.size()) a.push_back('0');
calc(b, b.size()-1, 1);
calc(a, a.size()-1, -1);
for(int i=b.size()-1;~i;i--)
{
tag[i]=(tag[i]+tag[i+1])%mod;
for(int j=0;j<10;j++)
cnt[i][j]=(cnt[i][j]+tag[i])%mod;
}
int64_t ans=0;
for(int i=b.size()-1;~i;i--)
for(int j=0;j<10;j++)
for(int k=j+1;k<10;k++)
ans=(ans+(k-j)*cnt[i][j]%mod*cnt[i][k])%mod;
cout<<ans*2%mod;
}

本文作者:Jimmy-LEEE

本文链接:https://www.cnblogs.com/redacted-area/p/18514171

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起