定义
r
e
v
(
i
)
rev(i)
rev(i)为i十进制下各位翻转所得的数,例如
r
e
v
(
2345
)
=
5432
,
r
e
v
(
3210
)
=
123
rev(2345)=5432,rev(3210)=123
rev(2345)=5432,rev(3210)=123。
l0nl1f3比较无聊,他打算用
r
e
v
rev
rev函数进行一个游戏。
他找了一个无穷大的表格,设第i行第j列的格子上的数为f(i,j),那么f满足
f
(
x
,
y
)
=
x
,
y
=
1
f(x,y)=x , y=1
f(x,y)=x,y=1
f
(
x
,
y
)
=
f
(
x
,
y
−
1
)
+
r
e
v
(
f
(
x
,
y
−
1
)
)
,
y
>
1
f(x,y) = f(x,y−1)+rev(f(x,y−1)),y>1
f(x,y)=f(x,y−1)+rev(f(x,y−1)),y>1
l0nl1f3想要知道这个表格中
[
L
,
R
]
[L,R]
[L,R]之间的数出现了多少次,
m
o
d
P
mod\ P
mod P输出。
由于他有时候会改变主意,所以他可能会询问q次,每次的L、R、P可能不同。
1
≤
q
≤
1
0
5
,
1
≤
L
≤
R
≤
1
0
10
,
1
≤
P
≤
1
0
9
1≤q≤10^5,1≤L≤R≤10^{10},1≤P≤10^9
1≤q≤105,1≤L≤R≤1010,1≤P≤109
这题很有NOIP模拟赛的意味啊(我说的是那种队爷都做不起的NOIPlus模拟赛)
首先小学奥数一波:
a
b
c
d
e
‾
+
e
d
c
b
a
‾
=
10001
(
a
+
e
)
+
1010
(
b
+
d
)
+
200
c
\overline {abcde} + \overline {edcba} = 10001(a+e)+1010(b+d)+200c
abcde+edcba=10001(a+e)+1010(b+d)+200c
从这个式子我们可以发现,可以被表示为
x
+
r
e
v
(
x
)
x+rev(x)
x+rev(x)的数应该是比较少的吧。
事实证明在
1
0
10
10^{10}
1010内有
3
∗
1
0
6
3*10^6
3∗106个,先用上面的式子搜出来(枚举
a
+
e
a+e
a+e,
b
+
d
b+d
b+d…)
然后我们再考虑每个数出现了多少次。
x
+
r
e
v
(
x
)
x+rev(x)
x+rev(x)会出现在
f
(
x
,
j
)
f(x,j)
f(x,j)中,同时
(
x
+
r
e
v
(
x
)
)
+
r
e
v
(
x
+
r
e
v
(
x
)
)
(x+rev(x))+rev(x+rev(x))
(x+rev(x))+rev(x+rev(x))也会,以此类推。
发现这
x
+
r
e
v
(
x
)
x+rev(x)
x+rev(x)递增,也就是这种关系有着及其强的拓扑关系。
设
d
p
[
x
]
dp[x]
dp[x]为x在
f
(
y
,
j
)
,
y
<
x
f(y,j),y<x
f(y,j),y<x中出现的次数。
那么
d
p
[
x
+
r
e
v
(
x
)
]
+
=
d
p
[
x
]
+
1
dp[x+rev(x)] += dp[x]+1
dp[x+rev(x)]+=dp[x]+1
这里的
x
x
x是任意
1
0
10
10^{10}
1010内的数,显然会炸。
只需要在前面搜索的时候算一下
g
(
x
)
=
∑
y
+
r
e
v
(
y
)
=
x
1
g(x) = \sum_{y+rev(y)=x} 1
g(x)=∑y+rev(y)=x1
然后
d
p
[
x
+
r
e
v
(
x
)
]
+
=
d
p
[
x
]
dp[x+rev(x)] += dp[x]
dp[x+rev(x)]+=dp[x]这时候的
x
x
x范围就是可以被表示为
y
+
r
e
v
(
y
)
y+rev(y)
y+rev(y)的数,一共
3
∗
1
0
6
3*10^6
3∗106个。
然后前缀和一下回答询问就行了。
时间复杂度:
O
(
3
∗
1
0
6
lg
(
3
∗
1
0
6
)
)
O(3*10^6\lg{(3*10^6)})
O(3∗106lg(3∗106))我也不知道sort为啥这么快
AC Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
char ch,B[1<<20],*S=B,*T=B;
#define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++)
#define isd(c) (c>='0'&&c<='9')
ll aa;ll F(){ //positive only.
while(ch=getc(),!isd(ch));aa=ch-'0';
while(ch=getc(),isd(ch))aa=aa*10+ch-'0';
return aa;
}
ll psb[3200000],sb[3200000],pw[20],psum[3200000],sum[3200000];
int c[3200000];
void dfs(int now,int lim,ll had,ll ways){
if(had > pw[10]) return;
if(now == (lim+1)/2){
psb[++psb[0]] = had , c[psb[0]] = psb[0] , psum[psb[0]] = ways;
//if(had == 110)
// printf("%d %d %lld %lld\n", now,lim,had,ways);
return;
}
if(!now){
if(pw[now] == pw[lim-now-1]){
for(int i=1;i<=9;i++)
dfs(now+1,lim,had+2*i*pw[now],ways);
}
else{
for(int i=1;i<=18;i++)
dfs(now+1,lim,had+i*(pw[now]+pw[lim-1-now]),ways*(i<=9?i:9-(i-10)));
}
}
else{
if(pw[now] == pw[lim-now-1]){
for(int i=0;i<=9;i++)
dfs(now+1,lim,had+2*i*pw[now],ways);
}
else{
for(int i=0;i<=18;i++)
dfs(now+1,lim,had+i*(pw[now]+pw[lim-1-now]),ways*(i<=9?i+1:9-(i-10)));
}
}
}
ll rev(ll x){
ll ret=0;
for(;x;) ret=ret*10+x%10,x/=10;
return ret;
}
bool cmp(const int &u,const int &v){ return psb[u] < psb[v]; }
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
pw[0] = 1;
for(int i=1;i<=10;i++) pw[i] = pw[i-1] * 10;
for(int i=1;i<=10;i++) dfs(0,i,0,1);
sort(c+1,c+1+psb[0],cmp);
for(int i=1;i<=psb[0]+1;i++)
if(psb[c[i]] == psb[c[i-1]])
psum[c[i]] += psum[c[i-1]];
else if(i>1)
sb[++sb[0]] = psb[c[i-1]] , sum[sb[0]] = psum[c[i-1]];
//for(int i=1;i<=200;i++)
//printf("%d %lld %lld\n",i,sb[i],sum[i]);
for(int i=1;i<=sb[0];i++){
//if(sb[i]+rev(sb[i]) == 11)
// printf("%d\n",sb[i]);
sum[lower_bound(sb+1,sb+1+sb[0],sb[i]+rev(sb[i]))-sb] += sum[i];
sum[i] += sum[i-1];
//if(i<=200)printf("%d %lld\n",i,sum[i]);
}
int q=F(),ans=0;
ll l,r,p;
for(;q--;){
l=F(),r=F(),p=F();
int ret = (sum[upper_bound(sb+1,sb+1+sb[0],r)-sb-1] - sum[upper_bound(sb+1,sb+1+sb[0],l-1)-sb-1] + r - l + 1) % p;
//printf("%d\n",ret);
ans ^= ret;
}
printf("%d\n",ans);
}