SAN
· 阅读需 5 分钟
[COCI 2015/2016 #6] SAN
题干
题目描述
有一张神秘的无限表,表里有无限行和无限列。有趣的是,表中的每个数字出现的次数是有限的。
定义函数 ,返回 在十进制下翻转后得到的新数字。例如 ,。
表中第 行第 列的数字 由以下方式得到:
-
-
,

现在 给出 个询问,每个询问给出两个整数 和 ,请你求出无限表中有多少个数的大小在 中。
输入格式
第一行包含一个整数 。
接下来 行,每行包含两个整数 和 。
输出格式
输出包含 行,每行一个整数,其中第 行为第 个问题的答案。
输入输出样例 #1
输入 #1
2
1 10
5 8
输出 #1
18
8
输入输出样例 #2
输入 #2
3
17 144
121 121
89 98
输出 #2
265
25
10
输入输出样例 #3
输入 #3
1
1 1000000000
输出 #3
1863025563
说明/提示
【数据范围】
对于 的数据,保证 。
对于 的数据,保证 ,。
【题目来源】
题目译自 COCI 2015-2016 CONTEST #6 T6 SAN。
本题分值按 COCI 原题设置,满分 。
分析
正解
我们很容易就能发现:能够被表示成的数并不在多数,也就是说,按照上面那一条转移式,大于的并不多,我们可以把这些大于的通过数位求出来,也是前缀和处理一下,然后二分查询即可
我们来考虑一下它的复杂度。假设我们现在枚举的在十进制下有位的,也就是
我们设一个数其从低到高的第位为,则有
设,在不进位的情况下满足下面这个条件:
而对于的任意一位,它都是由的某两位加和得到,故有结论:
那么的可能数就只有级别,总数大概在级别,实际上略多一点,为个
最后的复杂度就大概在:
其中
AC代码
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair< int,int >
#define QWQ return 0;
#define QAQ return
const int N=1e5+10, BIT=20;
const ll upper=1e10;
int C[2][BIT];
ll pow10[11];
map< ll,ll > sum;
inline ll rev( ll x )
{
ll num=0;
while( x ) num=num*10+x%10, x/=10;
QAQ num;
}
inline void dfs( int l,int r,ll num,bool flag,ll f )
{
if( num > upper )return;
if( l > r )
{ sum[num]+=f; QAQ; }
if( l == r )
{
for( int i=flag;i<=9;i++ ) sum[num+( pow10[l]*i<<1 ) ]+=f;
QAQ;
}
for( int i=flag;i<=18;i++ ) dfs( l+1,r-1,num+( pow10[l]+pow10[r] )*i,0,f*C[flag][i] );
}
inline void init()
{
pow10[0]=1;
for( int i=0;i<=9;i++ ) for( int j=0;j<=9;j++ ) C[1][i+j]+=( i > 0 ), C[0][i+j]++;
for( int i=1;i<=10;i++ ) pow10[i]=pow10[i-1]*10, dfs( 0,i-1,0,1,1 );
ll pre=0;
for( auto &x:sum )
{
ll y=x.first+rev( x.first );
if( y <= upper ) sum[y]+=x.second;
pre+=x.second; x.second=pre;
}
}
int main()
{
// freopen( "1.in","r",stdin );
// freopen( "1.out","w",stdout );
ios::sync_with_stdio( false );
cin.tie( nullptr ); cout.tie( nullptr );
init();
int q;
ll l, r;
for( cin>>q;q;q-- )
cin>>l>>r,
cout<<( --sum.upper_bound( r ) )->second-( --sum.lower_bound( l ) )->second + r-l+1<<"\n";
QWQ
}
