SAN
一道挺有价值的题,标的是数位DP但感觉不像呢,它感觉更像是一个递推和差分,DP倒真的说不上(毕竟它没有记忆化)。
首先第一列出现的元素是容易求的,但第二列似乎是麻烦的。但考虑一下发现,容易想到假如不考虑进位的话那么第二列的所有数应该都是回文数,而既然都是回文数了那么它的取值集合的大小就会大大减小,由于每一位都是在\([0,18]\)中的,回文数最多10位(也就是有5位是可选择的),那么取值应该是在\(18^5\) 级别的,甚至可以枚举。用dfs可以直接枚举出所有在第二列中出现的元素,然后这些元素的出现次数也是可以通过排列组合求得的。然后就考虑第三列第四列以及后面的东西。由于这个集合中的数那也是自然数(这不废话),它们经过变换后的数应该也在集合内,这就构成了一个树形结构,求数量就是求子树大小,递归即可。递归之后求前缀和就可以啦。
代码还好,不算太烧脑。
#include<bits/stdc++.h>
//#define feyn
#define int long long
const int M=8;
const int N=5000010;
const int S=1e11;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int min(int s1,int s2){
return s1<s2?s1:s2;
}
inline int p(int wh){
int cnt=0,c[12]={0};
while(wh)c[++cnt]=wh%10,wh/=10;
for(int i=1;i<=cnt;i++)wh=wh*10+c[i];
return wh;
}
struct node{
int data,an;
}s[N];
inline bool operator <(node s1,node s2){
return s1.data<s2.data;
}
int cnt;
int a[M],sa[20],sb[20];
inline void dfs(int wh){
if(wh>5)return;
if(wh){
//统计单数位
if(a[wh]%2==0){
int data=0,an=1;
for(int i=1;i<wh;i++){
data=data*10+a[i];
if(i==1)an=an*sb[a[i]];
else an=an*sa[a[i]];
}
for(int i=wh;i;i--)data=data*10+a[i];
s[++cnt]=(node){data,an};
//if(wh==1)printf("%lld %lld\n",data,an);
}
//统计偶数位
int data=0,an=1;
for(int i=1;i<=wh;i++){
data=data*10+a[i];
if(i==1)an=an*sb[a[i]];
else an=an*sa[a[i]];
}
for(int i=wh;i;i--)data=data*10+a[i];
s[++cnt]=(node){data,an};
//if(wh==2)printf("%lld %lld\n",data,an);
}
for(int i=(wh==0)?1:0;i<=18;i++){
a[wh+1]=i;dfs(wh+1);
}
}
inline int find(int wh){
//find the first one.data<=wh
int l=0,r=cnt,mid;
while(l<r)s[(mid=l+r+1>>1)].data<=wh?l=mid:r=mid-1;
//if(wh<=200)printf("find %lld %lld\n",wh,s[l].data);
return l;
}
inline int work(int wh){
return wh==0?0:wh+s[find(wh)].an;
}
signed main(){
#ifdef feyn
freopen("in.txt","r",stdin);
#endif
for(int i=0;i<10;i++)
for(int j=0;j<=18;j++)
if(j-i>=0&&j-i<=9){sa[j]++;if(i)sb[j]++;}
dfs(0);sort(s+1,s+cnt+1);
int cnt_=0;
for(int i=1;i<=cnt;i++){
if(s[i].data==s[i+1].data){
s[i+1].an+=s[i].an;
s[i].data=0;
}
if(s[i].data)s[++cnt_]=s[i];
}
//for(int i=1;i<=50;i++)printf("a %lld %lld\n",s[i].data,s[i].an);
//printf("working\n");
cnt=cnt_;
for(int i=1;i<=cnt;i++){
int data=s[i].data+p(s[i].data);
if(data>S)continue;
s[find(s[i].data+p(s[i].data))].an+=s[i].an;
}
for(int i=1;i<=cnt;i++){
s[i].an+=s[i-1].an;
}
//for(int i=1;i<=50;i++)printf("%lld %lld\n",s[i].data,s[i].an);
int m,l,r;read(m);
while(m--){
read(l);read(r);
printf("%lld\n",work(r)-work(l-1));
}
return 0;
}
一如既往,万事胜意