zoukankan      html  css  js  c++  java
  • 【HNOI2016】大数

    题面

    题解

    首先考虑如何判断一个区间内的数是否为一个数的倍数。

    (x_i)表示区间([i, n])组成的数。

    如果([l, r])内的数是质数(p)的质数,则:

    [frac{x_l - x_{r + 1}}{10 ^ {r - l + 1}} equiv 0 mod p ]

    (p eq 2, 5)时,(gcd(10, p) = 1)当且仅当

    [x_l - x_{r + 1} equiv 0 mod p ]

    [Leftrightarrow x_l equiv x_{r + 1} mod p ]

    时,区间([l, r])内的数是(p)的倍数。

    (p = 2)(p = 5)时,可以只通过最后一位有关,很好判断。

    于是这两种情况都可以直接莫队。

    注意权值要离散化。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define RG register
    #define clear(x, y) memset(x, y, sizeof(x))
    
    const int maxn(100010);
    struct qry { int l, r, blk, id; } q[maxn];
    long long ans, Ans[maxn]; char s[maxn];
    int val[maxn], a[maxn], Pow[maxn], num[maxn];
    int n, m, p, SIZE, L, R, cnt, tot;
    
    inline bool cmp(const qry &x, const qry &y)
    {
    	return x.blk == y.blk ? (x.blk & 1 ? x.r > y.r : x.r < y.r)
    		: x.blk < y.blk;
    }
    
    inline void insert(int x) { ans += num[val[x]], ++num[val[x]]; }
    inline void erase(int x) { --num[val[x]], ans -= num[val[x]]; }
    inline void insl(int x) { cnt += (s[x] - '0') % p == 0, ans += cnt; }
    inline void dell(int x) { ans -= cnt, cnt -= (s[x] - '0') % p == 0; }
    inline void insr(int x) { if((s[x] - '0') % p == 0) ++cnt, ans += R - L + 1; }
    inline void delr(int x) { if((s[x] - '0') % p == 0) ans -= R - L + 1, --cnt; }
    
    int main()
    {
    	scanf("%d%s%d", &p, s + 1, &m); n = strlen(s + 1); Pow[0] = 1;
    	for(RG int i = 1; i <= n; i++) Pow[i] = 10ll * Pow[i - 1] % p;
    	for(RG int i = n; i; i--) a[i] = val[i] = (val[i + 1] +
    			1ll * (s[i] - '0') * Pow[n - i]) % p;
    	std::sort(a + 1, a + n + 2); int _n = std::unique(a + 1, a + n + 2) - a - 1;
    	for(RG int i = 1; i <= n; i++)
    		val[i] = std::lower_bound(a + 1, a + _n + 1, val[i]) - a - 1;
    	SIZE = ceil(sqrt(n));
    	for(RG int i = 1; i <= m; i++)
    		scanf("%d%d", &q[i].l, &q[i].r),
    		q[i].blk = q[i].l / SIZE, q[i].id = i;
    	std::sort(q + 1, q + m + 1, cmp); L = 1, R = 0;
    	if(p != 2 && p != 5) for(RG int i = 1; i <= m; i++)
    	{
    		++q[i].r;
    		while(L > q[i].l) --L, insert(L);
    		while(R < q[i].r) ++R, insert(R);
    		while(L < q[i].l) erase(L), ++L;
    		while(R > q[i].r) erase(R), --R;
    		Ans[q[i].id] = ans;
    	}
    	else for(RG int i = 1; i <= m; i++)
    	{
    		while(L > q[i].l) --L, insl(L);
    		while(R < q[i].r) ++R, insr(R);
    		while(L < q[i].l) dell(L), ++L;
    		while(R > q[i].r) delr(R), --R;
    		Ans[q[i].id] = ans;
    	}
    	for(RG int i = 1; i <= m; i++) printf("%lld
    ", Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Unity3D中AssetBundle应用
    C++智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr
    C++枚举类型Enum及C++11强枚举类型用法
    C++强制类型转换
    Git使用(二、分支的创建和上传)
    Git使用(一、TortoiseGit和Gitlab在Windows下的项目库创建和上传)
    UE4行为树
    软件光栅器实现(四、OBJ文件加载)
    软件光栅器实现(三、裁剪)
    软件光栅器实现(二、VS和PS的运作,法线贴图,切空间的计算)
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10440164.html
Copyright © 2011-2022 走看看