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
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
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]);
}