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

HNOI2016 Day2 T3 大数(BZOJ4542)

时间:2016-05-02 00:40:06      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:

莫队算法

 

今天为了做这道题先去学了莫队算法,然后A掉了莫队算法的入门题目——小Z的袜子。

考场上面我傻逼的打了一个高精度,华丽丢掉暴力分。然而我发现只需要取个模就可以了,考场上傻了。

学完莫队算法之后,发现这道题其实就是一个裸题。

 

一开始依然是莫队算法的方式,按左端点所在块的编号为第一关键字,右端点编号为第二关键字排序,

考虑先暴力处理每个块的第一组询问,之后可以发现我们只需要微调一下区间的左右端点就可以了。比如说:我上次处理了1 5,那么1 6就可以只把6加进去就可以了;如果这一次是2 6,那么我还需要把1给去掉。

考虑怎么转移:先离散化一下余数,记录[l, r]中这个数出现了几次,区间长度±1时显然答案改变值为这个点的余数的原出现次数(假设第一个数余数为2,用cnt[2]表示余数为2的数在当前区间的出现次数,那么去掉1之后答案改变值为cnt[2],自己yy一下应该想得通的)。

然后好像很有道理了,AC了?!好吧,其实是善良的出题人没有卡我们,其实p = 2  或 p = 5的情况是可以被卡掉的

特判一下就好了,两个数组分别表示[1, i]中2或5的倍数时有多少种情况及有多少个数末尾是2或5的倍数,用前缀和维护。

这样就可以完美AC了,可以过掉BZOJ上的新增数据了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
const int MAXN = 100011;
const int MAXM = 100011;
int p,m;
int n;
char ch[MAXN];
LL ans[MAXN];
LL mi[MAXN];
int size;
int belong[MAXN];
LL hou[MAXN];
LL cnt[MAXN]
LL c[MAXN];
int tot;//È¥ÖغóµÄ³¤¶È
LL now;
LL jisuan1[MAXN],jisuan2[MAXN];

struct wen{
    int l,r,jilu;
    int k;
}Q[MAXM];

inline int getint(){
    char c=getchar();int w=0,q=0;
    while( (c<0 || c>9) && c!=- ) c=getchar();
    if(c==-) c=getchar(),q=1;
    while(c<=9 && c>=0) w=w*10+c-0,c=getchar();
    return q?-w:w;
}

bool cmp(wen q,wen qq){ if(q.k==qq.k) return q.r<qq.r; return q.k<qq.k; }

inline void init(){
    mi[n]=1;
    for(int i=n-1;i>=1;i--) mi[i]=mi[i+1]*10%p;

    size=sqrt(n); if(n!=size*size)  size++;
    hou[n+1]=0;
    for(int i=n;i>=1;i--) {
    belong[i]=(i-1)/size+1;
    hou[i]=hou[i+1]+(ch[i]-0)*mi[i]; hou[i]%=p;
    }

    memcpy(c,hou,sizeof(hou));

    sort(c+1,c+n+1+1);
    tot=unique(c+1,c+n+1+1)-c-1;
    
    for(int i=1;i<=n+1;i++) hou[i]=lower_bound(c+1,c+n+1+1,hou[i])-c;

    m=getint();
    for(int i=1;i<=m;i++) {
    Q[i].l=getint(),Q[i].r=getint(),Q[i].k=belong[Q[i].l],Q[i].jilu=i;
    Q[i].r++;//×¢Òâ¼ÓÒ»
    }
}

inline void update(int x,int type){
    now-=cnt[hou[x]]*(cnt[hou[x]]-1)/2;
    cnt[hou[x]]+=type;
    now+=cnt[hou[x]]*(cnt[hou[x]]-1)/2;
}

inline void work(){
    int l=1,r=0;

    sort(Q+1,Q+m+1,cmp);

    for(int i=1;i<=m;i++) {
        for(;r<Q[i].r;r++) update(r+1,1);
    for(;r>Q[i].r;r--) update(r,-1);
    for(;l<Q[i].l;l++) update(l,-1);
    for(;l>Q[i].l;l--) update(l-1,1);
    ans[Q[i].jilu]=now;
    }

    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}

inline void solve(){//¼ÇÒ»ÏÂǰ׺ºÍ
    m=getint();
    for(int i=1;i<=n;i++) { 
    jisuan1[i]=jisuan1[i-1]; jisuan2[i]=jisuan2[i-1];
    if( (ch[i]-0)%p==0 )
        {
        jisuan1[i]++;
        jisuan2[i]+=i;
        }
    //jisuan1[i]=jisuan1[i-1]+((ch[i]-‘0‘)%p==0),jisuan2[i]=jisuan2[i-1]+  (   ( (ch[i]-‘0‘)%p==0 )?i:0  );
   
    }
    for(int i=1;i<=m;i++) {
    int x=getint(),y=getint();
    printf("%lld\n",jisuan2[y]-jisuan2[x-1] - (x-1)*(jisuan1[y]-jisuan1[x-1]));
    }
}

int main()
{
   // freopen("number.in","r",stdin);
  //  freopen("number.out","w",stdout);
    p=getint();
    scanf("%s",ch+1); n=strlen(ch+1);
    //scanf("%s",ch); n=strlen(ch);
    //for(int i=n;i>=1;i--) ch[i]=ch[i-1];
    if(p!=2 && p!=5) {
    init();
    work();
    }
    else solve();

    return 0;
}

 

HNOI2016 Day2 T3 大数(BZOJ4542)

标签:

原文地址:http://www.cnblogs.com/ljh2000-jump/p/5451448.html

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