题面链接
题意:
给你一个 a a a,设 f ( i ) f(i) f(i)表示 i i i这个数十进制下各个数位的数字之和。要你求一对 ( l , r ) (l,r) (l,r),使得 ∑ i = l r f ( i ) = 0 ( m o d a ) \sum_{i=l}^rf(i)=0(mod\ a) ∑i=lrf(i)=0(mod a)。如果有多组合法的 ( l , r ) (l,r) (l,r),输出任意的一组。 a < = 1 e 18 , l , r < = 1 e 200 a<=1e18,l,r<=1e200 a<=1e18,l,r<=1e200。
题解:
这种可能有多组解的题,我们的思路当然是去构造一组解。我们考虑这个 f f f函数有什么性质。
性质1:
f ( i ) + 1 = f ( i + 1 0 x ) ( i < 1 0 x ) f(i)+1=f(i+10^x)\ (i<10^x) f(i)+1=f(i+10x) (i<10x) 很好理解,加上了 1 0 x 10^x 10x之后相当于在原数前面加了一个 1 1 1和若干个 0 0 0,那么各个数位的数字和增加了 1 1 1。
性质2:
∑ i = x + 1 x + 1 0 y f ( i ) = ∑ i = 1 1 0 y f ( i ) + x ( x < 1 0 y ) \sum_{i=x+1}^{x+10^y}f(i)=\sum_{i=1}^{10^y}f(i)+x\ (x<10^y) i=x+1∑x+10yf(i)=i=1∑10yf(i)+x (x<10y) 这个是在第一个性质的基础上的来的,我们可以把两边都有的那些 f ( i ) f(i) f(i)减去,那么我们就可以发现两边剩余的分别是 1 + 1 0 y 1+10^y 1+10y和 1 1 1, 2 + 1 0 y 2+10^y 2+10y和 2... x + 1 0 y 2...x+10^y 2...x+10y和 x x x。根据第一个性质,左边的每一项的函数值都比右边对应项的函数值大 1 1 1,总共加起来就大了 x x x。
有了这两个性质我们考虑怎么去构造答案。
我们先预处理出一个前缀和中 f ( i ) f(i) f(i)之和,当然我们这里只处理 1 1 1到所有 10 10 10的幂的前缀和结果,处理到 1 e 19 1e19 1e19,于是我们就算一下每个数字都出现了多少次,这样最后再乘上这个数值就可以了。我们考虑有了第二个式子能做什么,我们发现只要我们当前的这个 10 10 10的幂次的前缀和的答案加上一个小于当前幂次的数模 a a a能变成 0 0 0,那么我们就可以构造出一个答案。具体地,我们枚举每一个 y y y,若 a − ∑ i = 1 1 0 y m o d a < 1 0 y a-\sum_{i=1}^{10^y}mod\ a<10^y a−∑i=110ymod a<10y,那么我们就可以用第二个公式把当前区间左右端点整体加 a − ∑ i = 1 1 0 y m o d a a-\sum_{i=1}^{10^y}mod\ a a−∑i=110ymod a就可以构造出来了。
注意算的时候有些地方可能会爆long long,我们发现这个 f f f的前缀和其实是会爆long long的,但是由于最后我们只关心它模 a a a的答案,所以是可以取模的,就不会爆了。
最后吐槽一下,这个题我写完之后一直在炸long long,然后自己还不知道,小一点的数据就没问题,然后就找了个自己之前写过的数位dp当checker,发现自己写的并没有什么问题,就开始怀疑CF的checker写挂了。结果事实是,我的程序和checker都爆long long了。。。QAQ 再就是,我的这个题解可能和网上说的比较多的题解不太一样,写法上可能难写不少吧,好像别的题解都是一两行的样子。
代码:
#include <bits/stdc++.h>
using namespace std;
unsigned long long a,dp[20][20],mi[20],f[20],l,r;
int main()
{
cin>>a;
mi[0]=1;
for(int i=1;i<=19;++i)
mi[i]=mi[i-1]*10;
for(int i=1;i<=9;++i)
dp[0][i]=1;
for(int i=1;i<=19;++i)
{
for(int j=1;j<=9;++j)
dp[i][j]=dp[i-1][j]+dp[i-1][j]*9+mi[i];
}
for(int i=0;i<=18;++i)
{
for(int j=1;j<=9;++j)
{
f[i+1]=(f[i+1]+dp[i][j]*j%a)%a;
}
f[i]=(f[i]+1)%a;
}
for(int i=0;i<=19;++i)
{
if(a-f[i]%a<mi[i])
{
l=a-f[i]%a+1;
r=l+mi[i]-1;
break;
}
}
cout<<l<<" "<<r<<endl;
return 0;
}