欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【题解】NOIp模拟:数字

程序员文章站 2024-03-18 22:08:04
...

数字
(num.c/cpp/pas)

【问题描述】

一个数字被称为好数字当他满足下列条件:

1. 它有2*n个数位,n是正整数(允许有前导0)。

2. 构成它的每个数字都在给定的数字集合S中。

3. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等

例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。

已知n,求合法的好数字的个数mod 999983。

【输入格式】

第一行一个数n。

接下来一个长度不超过10的字符串,表示给定的数字集合。

【输出格式】

一行一个数字表示合法的好数字的个数mod 999983。

【样例输入】

2

0987654321

【样例输出】

1240

【数据规模】

对于20%的数据,n≤7。

对于100%的.据,n≤1000,|S|≤10。

先考虑前nn个和后nn个和相等的时候
dpi,jdp_{i,j}表示前ii位,总和为jj的方案数
dpi,j+ak+=dpi1,jdp_{i,j+a_k}+=dp_{i-1,j}
因为前后两部分相等,方案数为i=09ndpn,i2\sum_{i=0}^{9n}dp_{n,i}^2
然后把后部分插到前部分里面,相邻插入,可以得到奇偶相等,所以前后相等与奇偶相等是等价的,所以答案是i=09n2dpn,i2\sum_{i=0}^{9n}2dp_{n,i}^2

以上是没有去重的,我们发现两种情况会出现重复的情况
需要去重的是既满足前后相等,又满足奇偶相等的情况
把一排长度为2n2n的数列,切成4块,每块都有n2\frac{n}{2}个数,若nn是奇数的话,第一个块比第二个块多一个,第四个块比第三个块多一个
然后令这四个块的和分别为a,b,c,da,b,c,d
前后相等得到a+b=c+da+b=c+d
把后面一半插到前面一半,得到a+c=b+da+c=b+d
联立两式得到a=d,b=ca=d,b=c
所以枚举a,ba,b的值,这样的方案数就是dp[n2],a2dpn[n2],b2dp_{[\frac{n}{2}],a}^2*dp_{n-[\frac{n}{2}],b}^2
减掉这部分就好了

Code:

#include <bits/stdc++.h>
#define maxn 1010
#define maxm 9010
#define LL long long
using namespace std;
const int qy = 999983;
int n, a[maxn], m;
char s[maxn];
LL dp[2][maxm], f[maxm], g[maxm];

int main(){
	freopen("num.in", "r", stdin);
	freopen("num.out", "w", stdout);
	scanf("%d", &n);
	scanf("%s", s + 1);
	for (int i = 1; i <= strlen(s + 1); ++i) a[++m] = s[i] - 48;
	dp[0][0] = 1;
	for (int i = 1; i <= n; ++i){
		int now = i & 1, pre = now ^ 1;
		for (int j = 0; j <= 9 * i; ++j) dp[now][j] = 0;
		for (int j = 0; j <= 9 * (i - 1); ++j)
			for (int k = 1; k <= m; ++k) (dp[now][j + a[k]] += dp[pre][j]) %= qy;
		if (i == (n + 1) / 2) for (int j = 0; j <= i * 9; ++j) f[j] = dp[now][j];
		if ((n & 1) && i == n / 2) for (int j = 0; j <= i * 9; ++j) g[j] = dp[now][j];
	}
//	for (int i = 1; i <= 9 * (n >> 1); ++i) printf("%d\n", f[i]);
	int now = n & 1;
	LL ans = 0;
	for (int i = 0; i <= 9 * n; ++i) (ans += 2LL * dp[now][i] % qy * dp[now][i] % qy) %= qy;
	if (n & 1){
		int u = (n + 1) >> 1, v = n >> 1;
		for (int i = 0; i <= u * 9; ++i)
			for (int j = 0; j <= v * 9; ++j)
				ans = ((ans - f[i] * f[i] % qy * g[j] % qy * g[j] %  qy) % qy + qy) % qy;
	} else{
		int s = n >> 1;
		for (int i = 0; i <= 9 * s; ++i)
			for (int j = 0; j <= 9 * s; ++j) ans = ((ans - f[i] * f[i] % qy * f[j] % qy * f[j] % qy) % qy + qy) % qy;
	}
	printf("%lld\n", ans);
	return 0;
}