题意
给一个范围[L,R],求满足\(L\leq n \leq R\) 且 \(L\leq rev(n) \leq R\)的\(n\)的个数,其中\(rev(n)\)表示将\(n\)翻转\((123->321)\),多组询问\((L,R\leq 2^64-1)\)
思路
长这样的计数问题,没什么悬念考虑数位DP
只设\(f_{i,lim}\)表示处理到第\(i\)位是否顶上界似乎不太够,因为在转移过程中还需要知道倒过来的数的状态,所以再用个变量\(lim2\)记录倒过来的数的状况
因为从前向后确定数倒过来看是从后向前确定数,所以\(lim2\)有三个值:比当前上界小,顶上界,暂时大于上界,用\(0,1,2\)表示
仅仅这样做并不能很好的处理前缀0的情况(如0001倒过来看会变成1000,但实际上应该为1),所以我还用了一个变量\(zer\)表示第一个非零数出现的位置
状态即为\(f_{i,lim1,lim2,zer}\),一遍数位DP即可求出答案,递归边界返回值为1的条件为\(lim2 \neq 2\) 或 倒过来的限制R的位数比L多1
本题毒瘤,\(L,R\)会炸longlong,需要用unsigned longlong来做,随时都需要注意爆边界的情况qwq
考试的标程都是错的几个意思
#include<bits/stdc++.h> #define Min(x,y) ((x)<(y)?(x):(y)) #define Max(x,y) ((x)>(y)?(x):(y)) using namespace std; typedef unsigned long long ll; int T,t1,t2,d; ll L,R,wei[25]; ll dp[70][23][2][3];//第一个不是0的位置 //0:没碰到上界,1:顶上界,2:过上界 template <class T> void read(T &x) { char c; int sign=1; while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48; while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign; } int gw(ll x,int w) { if(w==20) return 1; return (x/wei[w-1])%10; } int get_dep(ll x) { int ret=0; while(x) {++ret; x/=10;} return ret; } ll dfs(int stp,int zer,int lim1,int lim2,ll l,ll r)//正数第stp位,第一个非零位置,顶上界,逆向 { if(stp==d+1) return ((lim2!=2 || (stp-zer<=19 && zer && r/wei[stp-zer]) ) && zer); if(dp[stp][zer][lim1][lim2]!=-1) return dp[stp][zer][lim1][lim2]; ll ret=0; int x=gw(l,d-stp+1),y=gw(r,zer?stp-zer+1:1); if(lim1) { int l2,l3=0; for(int i=0;i<=x;++i) { if(i>y) l2=2; else if(i==y) l2=(lim2==2 ? 2 : 1); else l2=0; if(i) l3=stp; ret+=dfs(stp+1,zer?zer:l3,i==x,l2,l,r); } } else { int l2,l3=0; for(int i=0;i<=9;++i) { if(i>y) l2=2; else if(i==y) l2=(lim2==2 ? 2 : 1); else l2=0; if(i) l3=stp; ret+=dfs(stp+1,zer?zer:l3,0,l2,l,r); } } return dp[stp][zer][lim1][lim2]=ret; } ll solve(ll L,ll R)//翻转前<=L,翻转后<=R { if(!L||!R) return 0; memset(dp,-1,sizeof(dp)); d=get_dep(L); return dfs(1,0,1,1,L,R); } int main() { freopen("reverse.in","r",stdin); freopen("reverse.out","w",stdout); read(T);read(t1);read(t2); wei[0]=1; for(int i=1;i<=19;++i) wei[i]=wei[i-1]*10; while(T--) { read(L);read(R); cout<<solve(R,R)+solve(L-1,L-1)-solve(R,L-1)-solve(L-1,R)<<endl; } return 0; }