P3962 [TJOI2013] 数字根

题意

定义一个数字 \(x\) 的数字根 \(f(x)\)\(f(x)=\left\{\begin{matrix}x,x<10\\f(sum(x)),x\ge10\end{matrix}\right.\),其中 \(sum(x)\) 表示 \(x\) 各个数位的和。
给一个 \(n\) 个数的序列 \(A=a_1,a_2,\dots,a_n\),定义一个区间的数字根 \(F(l,r)=f(\sum_{i=l}^ra_i)\)
\(q\) 次询问,每次给 \(l,r\),问区间 \([l,r]\) 的所有子区间数字根集合中,前 \(5\) 大不重复的值是多少。如果不足 \(5\) 个,用 \(-1\) 占位。
\(n\le100000\)\(q\le100000\)\(a_i\le10^9\)

思路

发现 \(x\) 的数字根为 \(x\mod9\),特别的如果 \(x\equiv0\pmod9\),那么 \(x\) 的数字根是 \(9\)
考虑先统计出区间内所有连续子区间数字根种类,即模 \(9\) 意义下的和有哪些。这是好做的,用莫队,开一个桶记录当前区间内前缀和的种类及其数量,再开一个桶统计当前区间内每个子区间和的种类及其数量,由于只会在首尾插入 / 删除,所以可以做到 \(\mathcal O(1)\) 更新。
注意:由于 \(0\) 的数字根是 \(0\),所以需要特殊处理。

代码

// Problem: P3962 [TJOI2013] 数字根
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3962
// Memory Limit: 125 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
template<int mod>struct Modint{
    int z;
    Modint(){z=0;}
    Modint(int x){x%=mod;z=x<0?x+mod:x;}
    Modint(long long x){x%=mod;z=x<0?x+mod:x;}
    Modint(short x){x%=mod;z=x<0?x+mod:x;}
    Modint(char x){x%=mod;z=x<0?x+mod:x;}
    Modint(bool x){x%=mod;z=x<0?x+mod:x;}
    friend Modint operator+(Modint t,Modint t2){Modint ans;ans.z=(t.z+t2.z)%mod;return ans;}
    friend Modint operator*(Modint t,Modint t2){Modint ans;ans.z=1ll*t.z*t2.z%mod;return ans;}
    friend Modint operator-(Modint t,Modint t2){Modint ans;ans.z=(t.z-t2.z)%mod;return ans;}
    Modint operator-()const{return (Modint){-z};}
    Modint operator<<(const int t)const{Modint ans;ans.z=(z<<t)%mod;return ans;}
    Modint operator>>(const int t)const{Modint ans;ans.z=(z>>t)%mod;return ans;}
    Modint&operator+=(const Modint t){z=(z+t.z)%mod;return *this;}
    Modint&operator*=(const Modint t){z=1ll*z*t.z%mod;return *this;}
    Modint&operator-=(const Modint t){z=(z-t.z)%mod;return *this;}
    Modint&operator<<=(const int t){z=(z<<t)%mod;return *this;}
    Modint&operator>>=(const int t){z=(z>>t)%mod;return *this;}
    Modint&operator++(){z++,z%=mod;return *this;}
    Modint&operator--(){z--,z%=mod;return *this;}
    Modint operator++(int){Modint ls=*this;z++,z%=mod;return ls;}
    Modint operator--(int){Modint ls=*this;z--,z%=mod;return ls;}
    friend Modint ksm(Modint a,int b){
        Modint ans=1;
        while(b){if(b&1) ans=ans*a;a=a*a,b>>=1;}
        return ans;
    }
    friend void read(Modint&z){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=(x*10ll+c-'0')%mod,c=getchar();
        f?x=-x:0;
        z.z=x;
    }
    friend void write(Modint x){x.z<0?x.z+=mod:0;write(x.z);}
    int val(){return z=(z+mod)%mod;}
};
const int maxn=100010,len=316;
#define M Modint<9>
int n,q,cnt1[10],cnt2[10],aa[maxn];
bool hv[maxn][10];
M a[maxn],sum[maxn];
struct node{
    int l,r,id;
    bool operator<(const node t)const{
        if(l/len==t.l/len) return r<t.r;
        return l<t.l;
    }
}qu[maxn];
void add_front(int u){
    if(aa[u]-aa[u-1]) return ;
    for(int i=0;i<9;i++) cnt1[(M(i)-sum[u-1]).val()]+=cnt2[i];
    cnt2[sum[u-1].val()]++;
}
void add_back(int u){
    if(aa[u]-aa[u-1]) return ;
    for(int i=0;i<9;i++) cnt1[(sum[u]-M(i)).val()]+=cnt2[i];
    cnt2[sum[u].val()]++;
}
void del_front(int u){
    if(aa[u]-aa[u-1]) return ;
    cnt2[sum[u-1].val()]--;
    for(int i=0;i<9;i++) cnt1[(M(i)-sum[u-1]).val()]-=cnt2[i];
}
void del_back(int u){
    if(aa[u]-aa[u-1]) return ;
    cnt2[sum[u].val()]--;
    for(int i=0;i<9;i++) cnt1[(sum[u]-M(i)).val()]-=cnt2[i];
}
signed main(){
    read(n);
    for(int i=1;i<=n;i++){
        read(aa[i]);
        a[i]=aa[i];
        if(aa[i]==0) aa[i]=1;
        else aa[i]=0;
    }
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i],aa[i]+=aa[i-1];
    read(q);
    for(int i=1;i<=q;i++) read(qu[i].l,qu[i].r),qu[i].id=i;
    sort(qu+1,qu+1+q);
    int l=1,r=1;
    cnt2[sum[0].val()]++;
    if(aa[1]==0) cnt2[sum[1].val()]++,cnt1[sum[1].val()]++;
    for(int i=1;i<=q;i++){
        while(r<qu[i].r) add_back(++r);
        while(l>qu[i].l) add_front(--l);
        while(r>qu[i].r) del_back(r--);
        while(l<qu[i].l) del_front(l++);
        for(int j=0;j<9;j++) if(cnt1[j]) hv[qu[i].id][j]=1;
    }
    for(int i=1;i<=q;i++){
        int cnt=0;
        if(hv[i][0]) write("9 "),cnt++;
        for(int j=8;j>=1;j--){
            if(cnt==5) break;
            if(hv[i][j]) write(j),write(" "),cnt++;
        }
        if(cnt!=5&&aa[qu[i].r]-aa[qu[i].l-1]){
            write("0 ");
            cnt++;
        }
        for(int c=cnt+1;c<=5;c++) write("-1 ");
        write("\n");
    }
    return 0;
}
posted @ 2026-06-03 20:08  Link-Cut_Trees  阅读(21)  评论(0)    收藏  举报