• JZOJ 4239. 【五校联考5day2】光棍 (Standard IO)


    题意

    满足如下条件中任意一个的数(x)是合法的:

    • (x)(a)的倍数。
    • (x)在十进制下的数位和是(a)的倍数。
    • (x)在十进制下某个数位是(a)

    其中(a)给定,(2leq a leq 9)

    现在给出(l,r,a),对于([l,r])中每个不合法的(x),求(sum x^2)
    (1leq l leq r leq 10^{18}, 2leq a leq 9)

    Solution

    这显然是数位dp对吧。。。

    但是呢我不会数位dp,至今还没写对过一题,于是今晚恶补了一下,发现也不是很难,套个记忆化搜索的模板就行了。

    首先可以转换一下问题,用([1,r])的答案减掉([1,l-1])的答案。
    但是题目要求统计不合法数的平方和,我们转换为求合法数的平方和,然后用所有数的平方和减去它(这个可以套公式(O(1))求)。

    dfs 的参数是下面几个:

    note dfs(int len, int zero, int flag, int mo1, int mo2, int app)
    {
    }
    

    其中len表示是从低到高第几位,zero表示是否有前导零,flag表示前面几位是不是顶着上界填的,mo1表示当前数对a取模的值,mo2表示当前数的数位和对a取模的值,app(appear)是个0/1状态,表示当前数数位里是否出现了a。

    先考虑满足条件的数的个数怎么求,显然套个模板就行了。

    再考虑满足条件的数的和怎么求,设后面的数位中某个满足条件的数为(b),现在你要填(a),后面还有(k)位待填,那么填完以后这个数就是(a*10^k+b),那么我们只需要知道后面的数位中:
    1.满足条件的数的个数
    2.满足条件的数的和
    就能够求出当前状态满足条件的数的和。

    再考虑满足条件的数的平方和怎么求,还是用上面的(a,b,k),那么((a*10^k+b)^2=a^2*10^{2k}+2*a*b*10^k+b^2)
    那也就是知道后面的数位中:
    1.满足条件的数的个数
    2.满足条件的数的和
    3.满足条件的数的平方和
    就能够求出当前状态满足条件的数的平方和。

    然后这题就解决了。

    Code

    那个(166666668)(6)的逆元,因为要做除法。还有(n)原本是(10^{18})级别的,如果不先模(P)就会爆long long,某gsm因此正解fst了。

    #include <cstdio>
    #include <cstring>
    
    typedef long long ll;
    const ll P = 1e9 + 7;
    
    int T, a, len, arr[20];
    ll l, r, pow[40];
    struct note { ll s1, s2, s3; } f[20][10][10][2][2];
    
    ll calc(ll n) { n %= P; return 166666668ll * n % P * (n + 1) % P * (2 * n + 1) % P; }
    
    note dfs(int len, int zero, int flag, int mo1, int mo2, int app)
    {
    	if (!len) return (note){(!mo1 || !mo2 || app), 0, 0};
    	if (!flag && ~f[len][mo1][mo2][app][zero].s1) return f[len][mo1][mo2][app][zero];
    	note ret = (note){0, 0, 0};
    	int mx = flag ? arr[len] : 9;
    	for (int i = 0; i <= mx; i++)
    	{
    		note tmp = dfs(len - 1, zero && !i, flag && i == arr[len], (mo1 * 10 + i) % a, (mo2 + i) % a, app || i == a);
    		ret.s1 = (ret.s1 + tmp.s1) % P;
    		ret.s2 = (ret.s2 + i * pow[len - 1] % P * tmp.s1 % P + tmp.s2) % P;
    		ret.s3 = (ret.s3 + i * i % P * pow[2 * (len - 1)] % P * tmp.s1 + i * pow[len - 1] % P * 2 % P * tmp.s2 % P + tmp.s3) % P;
    	}
    	if (!flag) f[len][mo1][mo2][app][zero] = ret;
    	return ret;
    }
    
    ll solve(ll n)
    {
    	memset(f, -1, sizeof(f));
    	len = 0;
    	ll tmp = calc(n);
    	while (n) arr[++len] = n % 10, n /= 10;
    	note ans = dfs(len, 1, 1, 0, 0, 0);
    	return (tmp - ans.s3 + P) % P;
    }
    
    int main()
    {
    	pow[0] = 1; for (int i = 1; i <= 38; i++) pow[i] = 1ll * pow[i - 1] * 10 % P;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%lld%lld%d", &l, &r, &a);
    		printf("%lld
    ", (solve(r) - solve(l - 1) + P) % P);
    	}
    	return 0;
    }
    
  • 相关阅读:
    python 编码问题
    关于网页划词翻译
    clang 编译 c++
    Java流(Stream)操作实例筛选、映射、查找匹配
    JAVA系列笔记十八之nohup实现后台运行程序
    VSCode汇总
    java jdk 国内下载镜像地址及安装
    LocalDate、LocalDateTime与timestamp、Date的转换
    List.sort()排序功能
    Java Array、List、Set互相转化
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/10336229.html
Copyright © 2020-2023  润新知