【SCOI2013】数数(数位DP)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xyyxyyx/article/details/102711674

文章目录

题意

Fish数数玩的规则是:

  1. 确定数数的进制B

  2. 确定一个数数的区间[L, R]

对于[L, R] 间的每一个数,把该数视为一个字符串,列出该字符串的每一个(连续的)子串对应的B进制数的值。

对所有列出的数求和。

思路

数数好题。又是一道我不会的数数题。。。

我的思路:考虑每一位的贡献,就是所有前缀的长度和×后缀的长度和×当前位置的数的权值。实在太烦了根本写不出来。

题解思路:考虑在一个已有的串后面加上一个数,增加的是所有的后缀的权值。记录到当前位置时的权值和,后缀权值和,数的个数和数的位数之和就可以方便的递推了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 20130427;
int B, n, m, a[N], b[N];
int f[N][2], g[N][2], h[N][2], c[N][2];

template<class T>inline void read(T &x){
	x = 0; bool fl = 0; char c = getchar();
	while (!isdigit(c)){if (c == '-') fl = 1; c = getchar();}
	while (isdigit(c)){x = (x<<3)+(x<<1)+c-'0'; c = getchar();}
	if (fl) x = -x;
}

void _minus()
{
	a[n]--;
	int i = n;
	while (a[i] < 0 && i >= 1){
		a[i] += B;
		a[i-1]--;
		i--;
	}
	if (i == 0){
		a[1] = 0;
		n = 1;
	}
	else{
		i = 1;
		while (a[i] == 0 && i <= n) i++;
		if (i > n) n = 1;
		else{
			for (int j = i; j <= n; ++ j)
				a[j-i+1] = a[j];
			n -= i-1;
		}
	}
	i = 1;
	while (b[i] == 0) i++;
	for (int j = i; j <= m; ++ j)
		b[j-i+1] = b[j];
	m -= i-1;
}

int calc(int x){
	return 1LL*x*(x+1)/2%mod;
}

int solve(int n, int *a)
{
	c[1][1] = 1; c[1][0] = a[1]-1; // c -> 数的个数
	h[1][1] = 1; h[1][0] = a[1]-1; // h -> 位数之和
	g[1][1] = a[1]; g[1][0] = calc(a[1]-1); // g -> 后缀权值和
	f[1][1] = a[1]; f[1][0] = calc(a[1]-1); // f -> 权值和
	for (int i = 2; i <= n; ++ i){
		c[i][0] = (1LL*c[i-1][0]*B%mod + 1LL*c[i-1][1]*a[i]%mod + B-1) % mod;
		c[i][1] = 1;
		h[i][0] = (1LL*h[i-1][0]*B%mod + 1LL*h[i-1][1]*a[i]%mod + c[i][0]) % mod;
		h[i][1] = h[i-1][1]+1;
		g[i][0] = (1LL*g[i-1][0]*B%mod*B%mod + 1LL*(h[i-1][0]+c[i-1][0]+1)*calc(B-1)%mod) % mod;
		if (a[i] >= 1) (g[i][0] += 1LL*g[i-1][1]*B%mod*a[i]%mod + 1LL*(h[i-1][1]+c[i-1][1])*calc(a[i]-1)%mod) %= mod;
		g[i][1] = (1LL*g[i-1][1]*B%mod + 1LL*(h[i-1][1]+c[i-1][1])*a[i]%mod) % mod;
		f[i][0] = (1LL*f[i-1][0]*B%mod + g[i][0]) % mod;
		if (a[i] >= 1) (f[i][0] += 1LL*f[i-1][1]*a[i]%mod) %= mod;
		f[i][1] = (f[i-1][1] + g[i][1]) % mod;
	}
	return (f[n][0] + f[n][1]) % mod;
}

int main()
{
	read(B);
	read(n);
	for (int i = 1; i <= n; ++ i)
		read(a[i]);
	read(m);
	for (int i = 1; i <= m; ++ i)
		read(b[i]);
	_minus();
	printf("%d\n", (solve(m, b)-solve(n, a)+mod)%mod);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/102711674