AtCoder Beginner Contest 158

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 101s1,102s2,103s3,104s4...,10nsn
则一段区间 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+...+ar1+ar
根据题意,我们要判定 s u m l , r ∗ 1 0 r sum_{l,r}*10^{r} suml,r10r 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=brbl1
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 (brbl1)10r m o d mod mod p = = 0 p==0 p==0,有
b r ∗ 1 0 r b_r*10^r br10r m o d mod mod p = = b l − 1 ∗ 1 0 r p==b_{l-1}*10^r p==bl110r 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==bl1 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,...bi1中有多个与 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 i1个机器人都已经被处理所产生的集合数,有两种转移:
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]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值