E - Divisible Substring
数组
s
s
s的元素为
s
1
,
s
2
,
s
3
,
s
4
.
.
.
s
n
s_1,s_2,s_3,s_4...s_n
s1,s2,s3,s4...sn
令数组
a
a
a为
1
0
−
1
∗
s
1
,
1
0
−
2
∗
s
2
,
1
0
−
3
∗
s
3
,
1
0
−
4
∗
s
4
.
.
.
,
1
0
−
n
∗
s
n
10^{-1}*s_1,10^{-2}*s_2,10^{-3}*s_3,10^{-4}*s_4...,10^{-n}*s_n
10−1∗s1,10−2∗s2,10−3∗s3,10−4∗s4...,10−n∗sn
则一段区间
l
,
r
l,r
l,r的和为
s
u
m
l
,
r
=
a
l
+
a
l
+
1
+
.
.
.
+
a
r
−
1
+
a
r
sum_{l,r}=a_l+a_{l+1}+...+a_{r-1}+a_r
suml,r=al+al+1+...+ar−1+ar
根据题意,我们要判定
s
u
m
l
,
r
∗
1
0
r
sum_{l,r}*10^{r}
suml,r∗10r
m
o
d
mod
mod
p
=
=
0
p==0
p==0
令数组
b
b
b为
a
1
,
a
1
+
a
2
,
a
1
+
a
2
+
a
3
,
.
.
.
,
a
1
+
a
2
+
.
.
.
+
a
n
a_1,a_1+a_2,a_1+a_2+a_3,...,a_1+a_2+...+a_n
a1,a1+a2,a1+a2+a3,...,a1+a2+...+an
那么一段区间
l
,
r
l,r
l,r的和可以表示为
s
u
m
l
,
r
=
b
r
−
b
l
−
1
sum_{l,r}=b_r-b_{l-1}
suml,r=br−bl−1
设
b
i
b_i
bi都是在
m
o
d
mod
mod
p
p
p意义下的,那么
(
b
r
−
b
l
−
1
)
∗
1
0
r
(b_r-b_{l-1})*10^r
(br−bl−1)∗10r
m
o
d
mod
mod
p
=
=
0
p==0
p==0,有
b
r
∗
1
0
r
b_r*10^r
br∗10r
m
o
d
mod
mod
p
=
=
b
l
−
1
∗
1
0
r
p==b_{l-1}*10^r
p==bl−1∗10r
m
o
d
mod
mod
p
p
p。
即
b
r
b_r
br
m
o
d
mod
mod
p
=
=
b
l
−
1
p==b_{l-1}
p==bl−1
m
o
d
mod
mod
p
p
p。
那么只需要做在访问
b
i
b_i
bi时,统计
b
0
,
b
1
,
.
.
.
b
i
−
1
b_0,b_1,...b_{i-1}
b0,b1,...bi−1中有多个与
b
i
b_i
bi相等即可(认为
b
0
=
=
0
b_0==0
b0==0),可以用
m
a
p
map
map实现。
但是
2
2
2和
5
5
5这两个模数比较特别,要单独处理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,mod,inv10;
char s[N];
unordered_map<int,int>vis;
ll qpow(ll a,ll n)
{
ll ans=1;
while(n)
{
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&mod);
inv10=qpow(10,mod-2);
scanf("%s",s+1);
if(mod==5)
{
ll ans=0;
for(int i=1;i<=n;i++)
if(s[i]=='5'||s[i]=='0') ans+=i;
printf("%lld\n",ans);
return 0;
}
else if(mod==2)
{
ll ans=0;
for(int i=1;i<=n;i++)
if((s[i]-'0')%2==0) ans+=i;
printf("%lld\n",ans);
return 0;
}
vis[0]++;
int sum=0;
ll ans=0,k=1;
for(int i=1;i<=n;i++)
{
k=k*inv10%mod;
sum=(sum+(ll)(s[i]-'0')*k%mod)%mod;
ans+=vis[sum];
vis[sum]++;
}
printf("%lld\n",ans);
}
F - Removing Robots
如果启动了机器人
i
i
i,那么会出现机器人连续一段的多个机器人都被连锁启动,记
n
e
x
i
nex_i
nexi为启动了机器人
i
i
i后最小的
j
j
j满足
j
>
i
j>i
j>i且机器人
j
j
j没有被启动,没有这样的
j
j
j则使
n
e
x
i
=
n
+
1
nex_i=n+1
nexi=n+1,那么启动了机器人
i
i
i,
i
i
i的转移只会转移到
j
j
j,如果不启动机器人
i
i
i,则
i
i
i的转移转移到
i
+
1
i+1
i+1。
设
f
i
f_i
fi表示前
i
−
1
i-1
i−1个机器人都已经被处理所产生的集合数,有两种转移:
f
i
−
>
f
i
+
1
f_i->f_{i+1}
fi−>fi+1(不启动机器人
i
i
i)。
f
i
−
>
f
n
e
x
i
f_i->f_{nex_i}
fi−>fnexi(启动机器人
i
i
i)。
最后
f
n
+
1
f_{n+1}
fn+1则是答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=998244353;
int n,hs[N],nex[N],t[N<<2];
ll f[N];
struct node
{
int l,r;
bool operator<(const node&o)const{return l<o.l;}
}a[N];
void fix(int l,int r,int k,int x,int v)
{
if(l==r)
{
t[k]=max(t[k],v);return;
}
int m=l+r>>1;
if(x<=m) fix(l,m,k<<1,x,v);
else fix(m+1,r,k<<1|1,x,v);
t[k]=max(t[k<<1],t[k<<1|1]);
}
int query(int l,int r,int k,int x,int y)
{
if(r<x||l>y) return 0;
if(l>=x&&r<=y) return t[k];
int m=l+r>>1;
return max(query(l,m,k<<1,x,y),query(m+1,r,k<<1|1,x,y));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y;scanf("%d%d",&x,&y);
y=x+y-1;
a[i]={x,y};
hs[i]=x;
}
sort(a+1,a+1+n);
sort(hs+1,hs+1+n);
nex[n]=n+1;
fix(1,n,1,n,nex[n]);
for(int i=n-1;i>=1;i--)
{
int l=lower_bound(hs+1,hs+1+n,a[i].l)-hs,r=upper_bound(hs+1,hs+1+n,a[i].r)-hs-1;
nex[i]=max(r+1,query(1,n,1,l,r));
fix(1,n,1,i,nex[i]);
}
f[1]=1;
for(int i=1;i<=n;i++)
{
f[i+1]=(f[i+1]+f[i])%mod;
f[nex[i]]=(f[nex[i]]+f[i])%mod;
}
printf("%lld\n",f[n+1]);
}