• 题解 [HNOI2016]大数


    题目传送门

    题目大意

    给出一个(n)个数的字符串,有(m)次查询,对于该串的子串([l,r])有多少个子串满足是固定素数(p)的倍数。

    思路

    其实很简单,但是一开始想偏了。。。果然还是自己菜啊。。。

    我们可以想到统计一下后缀和(s[i]),表示([i,n])构成的数,那么,判断一个区间([l,r])是不是(p)的倍数就等价于:

    [dfrac{s[l]-s[r+1]}{10^{n-r}}equiv 0 pmod p ]

    我们发现如果(gcd(10,p)=1)的话,分母就不会产生影响,于是判断条件就是:

    [s[l]equiv s[r+1]pmod p ]

    于是对于这种情况我们就可以用莫队(Theta(nsqrt n))开桶记录答案。

    如果(gcd(10,p) ot=1)的话,那么(p=2 operatorname{or} 5),我们发现这种情况对于区间([l,r])判断是否的话直接判断第(r)位是不是(2operatorname{or}5)的倍数即可。于是我们可以(Theta(n))解决这种情况。

    果然还是自己菜了啊。。。这都没有看出来。。。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define ll long long
    #define MAXN 200005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    char S[MAXN];
    ll sum,ans[MAXN];int n,m,p,un,s[MAXN],tmp[MAXN],bel[MAXN],cnt[MAXN];
    
    namespace Subtask1{
    	struct node{
    		int l,r,id;
    		bool operator < (const node &p)const{return bel[l] != bel[p.l] ? l < p.l : r < p.r;}
    	}q[MAXN];
    	void cge (int x,int k){sum -= 1ll * cnt[x] * (cnt[x] - 1) / 2,cnt[x] += k,sum += 1ll * cnt[x] * (cnt[x] - 1) / 2;}
    	void Work (){
    		int siz = sqrt (n);
    		for (Int i = n,c = 1;i;-- i,c = 1ll * c * 10 % p) s[i] = (s[i + 1] + 1ll * c * (S[i] - '0') % p) % p,bel[i] = (i - 1) / siz + 1,tmp[i] = s[i];
    		sort (tmp + 1,tmp + n + 2);un = unique (tmp + 1,tmp + n + 2) - tmp - 1;for (Int i = 1;i <= n + 1;++ i) s[i] = lower_bound (tmp + 1,tmp + un + 1,s[i]) - tmp;
    		read (m);for (Int i = 1;i <= m;++ i) read (q[i].l,q[i].r),q[i].r ++,q[i].id = i;sort (q + 1,q + m + 1);int l = 1,r = 0;
    		for (Int i = 1;i <= m;++ i){
    			while (l < q[i].l) cge (s[l ++],-1);while (l > q[i].l) cge (s[-- l],1);
    			while (r < q[i].r) cge (s[++ r],1);while (r > q[i].r) cge (s[r --],-1);
    			ans[q[i].id] = sum;
    		}
    		for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('
    ');
    		return ;
    	}
    }
    
    namespace Subtask2{
    	int snum[MAXN];ll ssum[MAXN];
    	void Work(){
    		for (Int i = 1;i <= n;++ i){
    			snum[i] = ((S[i] - '0') % p == 0);
    			ssum[i] = ssum[i - 1] + 1ll * ((S[i] - '0') % p == 0) * i;
    		}
    		read (m);
    		while (m --){
    			int l,r;read (l,r);
    			write (ssum[r] - ssum[l - 1] - (snum[r] - snum[l - 1]) * (l - 1)),putchar ('
    ');
    		}
    	}
    }
    
    signed main(){
    	read (p),scanf("%s",S + 1),n = strlen (S + 1);
    	if (p == 2 || p == 5) Subtask2::Work ();
    	else Subtask1::Work ();
    	return 0;
    }
    
  • 相关阅读:
    springboot笔记
    SpringBoot
    SpringBoot整合JPA
    Docker
    SpringMVC学习04:异常处理和拦截器
    SpringMVC学习03:文件上传
    SpringMVC学习02:响应数据和结果视图
    Mybatis学习04
    【java基础】初步理解面向对象、类、对象
    【Java基础】方法的重载
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13370696.html
Copyright © 2020-2023  润新知