Description
Anica 做了一个很奇怪的梦:她梦见了一个无限大的平板,平板上填着无限行和无限列的整数。有趣的是,每个整数在那神奇的平板上只出现有限的次数。
机智的Anica很快便发现了这其中数字的规律,每一行第一列的数字表示当前的行号,其它非第一列的数字,为该位置左边一列的数字加上其数字的翻转数字之和。为了方便描述,我们定义A[i,j]表示平板上第i行第j列的数字:
1. A[i,1] = i,
2. A[i,j] = A[i,j-1] + Rev( A[i,j-1] ), 其中Rev(x)表示x在10进制下的翻转,例如Rev(213) = 312, Rev(406800) = 008604 = 8604 。
然而,Anica对这堆数字不太感兴趣。她看了一下平板的背面,并发现了一盏神灯,同时神灯也发现了Anica,这时一个精灵冒了出来:
精灵:“Anica,如果你能答对我Q个问题,你将获得一份神秘的礼物,否则你将无法无法醒来,哈哈哈哈~~”
精灵:“每个问题将给你两个整数A和B,请问区间[A,B]的数字总共在平板上出现了多少次?”
Anica:“我不想要你的礼物,我只想要醒过来,我还有很多事情要做呢!”
Input
第一行给出一个整数Q (1 <= Q <=10^5),表示问题的数量。
接下来Q行,每行两个整数A,B (1 <= A,B <= 10^10),表示每个询问的区间[A,B]。
Output
输出Q行,第i行一个整数,表示第i个询问的答案。
Sample Input
样例输入1:
2
1 10
5 8
样例输入2:
3
17 144
121 121
89 98
样例输入3:
1
1 1000000000
Sample Output
样例输出1:
18
8
样例输出2:
265
25
10
样例输出3:
1863025563
Data Constraint
50%的分数保证1 <= A,B <= 10^6。
Solution
对于50%:发现数据比较小,暴力。直接暴力第一列的数,每次f[x+rev(x)]+=f[x]。对f求前缀和,每次询问就是f[r]-f[l-1]。比较简单。
对于100%:
同样是暴力,但是要特别一点。
可以发现,总共的数的数量不会超过
195
,等会证明。那么,如何暴力这些数呢?
如果
x长为L=a1 a2 a3.. aL
rev(x)=aL aL-1 .. a1
x+rev(x)=a1+aL a2+aL-1 a3+aL-2 aL+a1
得到一个对称的数。L最大为10,那么一半就是5。分别为0~18中一个共19个,所以大约有
195
个数。
爆搜这些数,算出它在第二列时有多少种可能从第一列转移过来,存到f里面。接着同50分一样,最后二分一下就行了。
注意:存数用hash,表开大一点。最好所有数组与变量开longlong。
code
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define ll long long
#define mo 6412345
using namespace std;
struct note
{
ll x,y;
};
note a[mo];
ll b[6],hsh[mo+5],has[mo+5],len,k=0,c[19],tot=0;
ll rev(ll x)
{
ll jy=0;
for(;x;x/=10) jy=jy*10+x%10;
return jy;
}
ll hash(ll x)
{
ll y;
y=x%mo+1;
while (hsh[y]!=0 && hsh[y]!=x) y=(y+1)%mo;
return y;
}
void dg(int j)
{
if (j>len)
{
ll x=1,y=0;
fo(i,1,len)
{
ll jy=c[b[i]];
if (i==1 && b[i]<10) jy--;
if (i==len && k%2==1)
{
if(b[i]%2==1) jy=0;
else jy=1;
}
x*=jy;
if (i!=len) y=y*10+b[i];
}
if (x==0) return;
if (k%2==0) y=y*10+b[len];
for(int i=len;i>=1;i--) y=y*10+b[i];
ll jy=hash(y);
if (hsh[jy]==0) a[++tot].x=y,a[tot].y=x,hsh[jy]=y,has[jy]=tot;
else a[has[jy]].y+=x;
return;
}
ll kk;kk=j==1?1:0;
fo(i,kk,18)
{
b[j]=i;dg(j+1);
}
}
bool cmp(note x,note y){return x.x<y.x;}
ll find(ll l,ll r,ll k)
{
ll mid;
for(;l+1<r;)
{
mid=(l+r)/2;
if (a[mid].x<=k) l=mid;else r=mid;
}
if (a[r].x<=k) l=r;return l;
}
int main()
{
freopen("table.in","r",stdin);freopen("table.out","w",stdout);
fo(i,0,9)
fo(j,0,9) c[i+j]++;
for(len=1;len<=5;len++)
{
k++;dg(1);k++;dg(1);
}
sort(a+1,a+1+tot,cmp);
fo(i,1,tot)
{
ll x=a[i].x;x=x+rev(x);
if (x<=a[tot].x) a[find(0,tot,x)].y+=a[i].y;
}
fo(i,1,tot) a[i].y+=a[i-1].y;
int ak;scanf("%d",&ak);
while (ak-->0)
{
ll l,r;scanf("%lld%lld",&l,&r);
ll x=find(0,tot,r);ll y=find(0,tot,l);
if (a[y].x==l) y--;
printf("%lld\n",a[x].y-a[y].y+r-l+1);
}
fclose(stdin);fclose(stdout);
}