• 洛谷 P4127


    题目链接: P4127 [AHOI2009]同类分布

    题目大意

    详见题目

    solution

    我感觉这题比一般的数位DP紫题要难一点, 因为维数是 (4) 维(我懒得压维了)

    (f_{i, j, k, p}) 表示长度为 (i) 最高位为 (j) 的和为 (k) 对某一个数取模的余数为 (p) 的非萌数的个数

    显然有:
    (f_{i + 1, p, j + p, (p * 10^i + k) \% x} = sumlimits_{t = 0}^{t leqslant 9} f_{i, t, j, k})

    (t) 表示上一位填的数, (i) 是位数, (p) 是这一位填的数, (j) 是数位和, (k) 是对当前枚举的数位和取模之后的值, (x) 表示当前枚举的数位和

    然后 solve 进行计算即可. 策略如下:

    1. 对于位数小于当前位的, (res += f_{i, 10, x, 0} - f_{i, 0, x, 0})
    2. 对于位数相同的, 计算小于最高位的 (res += f_{num_s, p, x, 0})
    3. 然后对于当前不同的一位进行讨论即可, 计算出后面所需要的余数, 然后加和

    (num_s) 是最高位, (x) 是要求的位数和

    答案就是所有位数和的 (res) 之和, 同时满足满足([l,r])

    参考自: asuldb

    Code:

    /**
    *    Author: Aliemo
    *    Data: 
    *    Problem: 
    *    Time: O()
    */
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    #define int long long
    #define rr register
    
    #define inf 1e9
    #define MAXN 100010
    
    using namespace std;
    
    inline int read() {
    	int s = 0, f = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void print(int x) {
    	if (x < 0) putchar('-'), x = -x;
    	if (x > 9) print(x / 10);
    	putchar(x % 10 + 48);
    }
    
    int l, r, mod, ans;
    
    int num[2], base[20];
    
    int a[20][2];
    
    int f[20][11][172][172];
    
    inline void spilt(int x, int s) {
    	num[s] = 0;
    	while (x) a[++num[s]][s] = x % 10, x /= 10;
    }
    
    inline void init(int x, int len) {
    	mod = x;
    	memset(f, 0, sizeof f);
    	for (rr int i = 0; i <= 9; i++) 
    		f[1][i][i][i % mod]++, f[1][10][i][i % mod]++;
    	for (rr int i = 1; i < len; i++)
    		for (rr int j = 0; j <= min(x, i * 9); j++)
    			for (rr int k = 0; k < x; k++) {
    				if (!f[i][10][j][k]) continue;
    				for (rr int p = 0; p <= 9; p++) {
    					f[i + 1][p][j + p][(p * base[i] + k) % x] += f[i][10][j][k];
    					f[i + 1][10][j + p][(p * base[i] + k) % x] += f[i][10][j][k];
    				}
    			}
    }
    
    inline int solve(int s, int x) {
    	int tot = 0;
    	for (rr int i = 1; i < num[s]; i++) tot += f[i][10][x][0] - f[i][0][x][0];
    	for (rr int i = 1; i < a[num[s]][s]; i++) tot += f[num[s]][i][x][0];
    	int now = a[num[s]][s], cnt = now;
    	if (x - now < 0) return tot;
    	for (rr int i = num[s] - 1; i; i--) {
    		int t = (x - cnt * base[i] % x) % mod;
    	// cout << i << "
    ";
    		for (rr int j = 0; j < a[i][s]; j++) tot += f[i][j][x - now][t];
    		now += a[i][s];
    		cnt = cnt * 10 + a[i][s];
    		cnt %= mod;
    		if (x - now < 0) break;
    	}
    	return tot;
    }
    
    signed main() {
    	l = read(), r = read();
    	spilt(l, 0), spilt(r + 1, 1);
    	base[0] = 1;
    	for (rr int i = 1; i <= 18; i++) base[i] = base[i - 1] * 10;
    	for (rr int i = 1; i <= num[1] * 9; i++){
    		init(i, num[1]);
    		ans += solve(1, i) - solve(0, i);
    	}
    	cout << ans;
    }
    
  • 相关阅读:
    js变量声明提前
    03通讯录(Block传值)
    03-Block
    03通讯录(搭建编辑界面)
    03通讯录(代理解耦)
    03通讯录(逆传)
    03通讯录
    源码0604-06-掌握-大文件断点下载(断点下载)
    源码0604-05-程序不死
    源码0604-02-了解-网页开发
  • 原文地址:https://www.cnblogs.com/lieberdq/p/13996491.html
Copyright © 2020-2023  润新知