解题思路
首先我们要知道,求总合法的不能只简单的把两种情况的个数直接相加得到,因为他们有交集,要用容斥原理把它们的交集减去。( P s : 1221 Ps:1221 Ps:1221 这个串,前后位和奇偶位都相等。)
预处理: d p [ i ] [ j ] dp[i][j] dp[i][j]代表在集合中选i个数,i个数的和为j的时候一共有多少种方案数.
状态转移方程:
d
p
[
i
,
j
]
=
∑
(
d
p
[
i
−
1
,
j
−
S
[
k
]
]
)
(
i
=
1
dp[i,j]=∑(dp[i-1,j-S[k]]) (i=1
dp[i,j]=∑(dp[i−1,j−S[k]])(i=1~
n
,
j
=
0
n, j=0
n,j=0~
m
a
x
n
u
m
∗
i
,
k
=
1
∣
S
∣
)
maxnum*i, k=1~|S|)
maxnum∗i,k=1 ∣S∣)
(maxnum为S中最大的数,因为最大能组成的和为
2
∗
n
∗
m
a
x
n
u
m
2*n*maxnum
2∗n∗maxnum)
则"前n位之和与后n位之和相等”和“奇数位之和与偶数位之和相等”的个数都是
∑
i
=
0
m
a
x
n
u
m
∗
n
d
p
[
n
]
[
i
]
∑^{maxnum∗n}_{i=0}dp[n][i]
∑i=0maxnum∗ndp[n][i]
a
n
s
+
=
∑
i
=
0
m
a
x
n
u
m
∗
n
d
p
[
n
]
[
i
]
∗
2
ans+=∑^{maxnum∗n}_{i=0}dp[n][i]∗2
ans+=∑i=0maxnum∗ndp[n][i]∗2
接着考虑两种都符合的情况:假设前n个数中奇数位之和为a,偶数位之和为b,后n个数中奇数位之和为c,偶数位之和为d,易得:
a
+
b
=
c
+
d
,
a
+
c
=
b
+
d
a+b=c+d,a+c=b+d
a+b=c+d,a+c=b+d
所以:
b
=
c
,
a
=
d
b=c,a=d
b=c,a=d
描述:前一块中的奇数和等于后一块的偶数和,前一块的偶数和等于后一块的奇数和
因为n可能是奇数,所以令k1为奇数块规模,k2为偶数块规模,我们发现这和之前的问题是一样的, k 1 = ( n + 1 ) / 2 , k 2 = n / 2 k1=(n+1)/2,k2=n/2 k1=(n+1)/2,k2=n/2
则对“前一块中的奇数和等于后一块的偶数和”这一步的答案为 ∑ m a x n u m ∗ m a x i = 0 d p [ k 1 ] [ i ] ∗ d p [ k 1 ] [ i ] ∑_{maxnum∗max}^{i=0}dp[k1][i]∗dp[k1][i] ∑maxnum∗maxi=0dp[k1][i]∗dp[k1][i] (手推一下可以知道无论n的奇偶前一块中的奇数个数等于后一块的偶数个数)
对“前一块的偶数和等于后一块的奇数和”的答案同样是上一行。
把两个答案乘起来即为之前两块的交集 a n s 1 ans1 ans1, a n s − = a n s 1 ans-=ans1 ans−=ans1
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
#define ldb long double
using namespace std;
const ll mod=999983;
ll ans,ans1,ans2,d[1010][9010];
int l,c,n,k1,k2;
char s[15];
int main(){
scanf("%lld",&n);
scanf("%s",s+1);
l=strlen(s+1);
for(int i=1;i<=l;i++)
c=max(c,s[i]-'0');
d[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i*c;j++)
{
for(int k=1;k<=l;k++)
{
if(j>=s[k]-'0')
d[i][j]=(d[i][j]+d[i-1][j-(s[k]-'0')])%mod;
}
}
}
for(int i=0;i<=n*c;i++)
ans=(ans+d[n][i]*d[n][i]%mod)%mod;
ans=ans*2%mod;
k1=(n+1)/2,k2=n/2;
for(int i=0;i<=c*k1;i++)
ans1=(ans1+d[k1][i]*d[k1][i]%mod)%mod;
for(int i=0;i<=c*k2;i++)
ans2=(ans2+d[k2][i]*d[k2][i]%mod)%mod;
ans1=ans1*ans2%mod;
printf("%lld",(ans+mod-ans1)%mod);
}