码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P3962 [TJOI2013]数字根 st

时间:2018-08-05 21:33:24      阅读:245      评论:0      收藏:0      [点我收藏+]

标签:put   const   pac   include   therefore   lse   name   前缀   namespace   

题面

我先对数字根打了个表,然后得到了一个结论:\(a\)的数字根=\((a-1)mod 9+1\)

我在询问大佬后,大佬给出了一个简单的证明:

\(\because 10^n\equiv 1(mod 9)\)

\(\therefore a_{n}*10^n+a_{n-1}*10^{n-1}+...+a_{1}\equiv a_{n}+a_{n-1}+...+a_{1}(mod 9)\)

这样的话一个区间\([l,r]\)的数字根就可以转化为\((pre_{r}-pre_{l-1}-1)mod 9+1\)\(pre_{i}\)表示前缀和。

考虑预处理出一个数组\(last_{i,j}\)表示右端点为\(i\)数字根为\(j\)的区间的左端点的\(max\)

但是这样的话按原式子做感觉很麻烦。

所以再把这个式子拆一下得:\((pre_{r}-pre_{l-1}-1)mod 9+1\)=\(((pre_{r}-1)mod 9-pre_{l-1}mod 9+9)mod 9+1\)

这样就好搞多了。

那处理出来这个\(last\)有什么用呢...

考虑如果查询一个区间内是否存在一个子区间的数字根为\(j\)的话,我们只要查询\(max(last_{i,j})<=l(i\in[l,r])\)就行了。

那么只要求和区间max是否\(<=l\)就行了,\(st\),线段树随便上吧。

网上另外两篇题解都是暴力是smg,\(10^5\)\(0\)随便卡啊

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,u) for (register int i=first[u];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!=‘-‘)&&(ch!=EOF)) ch=getchar();
    if (ch==‘-‘){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
    return x*f;
}
const int N = 1e5+10;
int n,a[N];
ll pre[N];
inline void rd(){
    n=read();
    For(i,1,n) a[i]=read(),pre[i]=pre[i-1]+a[i];
}
int Log[N],last[N][10],now[10],p[20],Max[N][20][10];
inline void init(){
    For(i,1,8) now[i]=-1;
    For(i,1,n){
        if (!a[i]){For(j,1,9) last[i][j]=last[i-1][j];last[i][0]=i-1;}
            else{For(j,0,8) last[i][((pre[i]-1)%9-j+9)%9+1]=now[j];last[i][0]=-1;}
        now[pre[i]%9]=i;
        //For(j,1,9) printf("%d ",last[i][j]);puts("");
    }
    For(i,1,n) Log[i]=log2(i);
    p[0]=1;
    For(i,1,Log[n]) p[i]=p[i-1]<<1;
    For(i,1,n)
        For(j,0,9) Max[i][0][j]=last[i][j];
    For(j,1,Log[n])
        For(i,1,n-p[j]+1)
            For(k,0,9) Max[i][j][k]=max(Max[i][j-1][k],Max[i+p[j-1]][j-1][k]);
}
inline int query(int l,int r,int k){
    int L=Log[r-l+1];
    return max(Max[l][L][k],Max[r-p[L]+1][L][k]);
}
int q,l,r,cnt;
inline void work(){
    q=read();
    while (q--){
        l=read(),r=read(),cnt=0;
        Dow(i,9,0)
            if (query(l,r,i)+1>=l){
                printf("%d ",i),cnt++;
                if (cnt==5) break;
            }
        For(i,cnt+1,5) printf("-1 ");puts("");
    }
}
int main(){
    rd(),init(),work();
}

Luogu P3962 [TJOI2013]数字根 st

标签:put   const   pac   include   therefore   lse   name   前缀   namespace   

原文地址:https://www.cnblogs.com/zykykyk/p/9426992.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!