题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5389
题意:给出n个数和两个值A,B,要求将n个数分成两部分,使得每部分数和的数根的值等于A和B,求种数
解法:DP。 dp[i][j]表示取前i个数字中的若干个,按给定规则,算出来的和为j的方案数,dp[i][j]=dp[i-1][j]+dp[i-1][tmp](tmp为j-arr[i],若小于等于0,需加9调整),转移注意一个特殊的地方,就是当前位可以取并且前面都不取的情况,还有就是当a+b==a的时候,如果直接输出dp[n][a]不对,因为遗漏了a中都不取都放到b里面,而b恰好和sum相同的情况,这里的sum就是总和的数根。当总和和a+b不等时需要特殊处理。
#include <bits/stdc++.h>
using namespace std;
const int mod = 258280327;
const int maxn = 1e5+10;
int t, n, a, b, dp[maxn][11];
int val[maxn];
int cal(int x){
int ret = 0;
while(x){
ret += x%10;
x /= 10;
}
if(ret > 9) return cal(ret);
else return ret;
}
int main()
{
scanf("%d", &t);
while(t--)
{
int sum = 0;
scanf("%d %d %d", &n,&a,&b);
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; i++) scanf("%d", &val[i]), sum+=val[i];
sum = cal(sum);
int xx = cal(a+b);
if(sum == xx){
dp[1][val[1]] = 1;
dp[1][0] = 1;
for(int i=2; i<=n; i++){
dp[i][0] = 1;
for(int j=1; j<10; j++){
int tmp = j-val[i];
if(tmp < 0){
tmp += 9;
dp[i][j] = (dp[i-1][tmp] + dp[i-1][j])%mod;
}
else if(tmp == 0){
dp[i][j] = (dp[i-1][j] + dp[i-1][9] + dp[i-1][0])%mod;
}
else{
dp[i][j] = (dp[i-1][j] + dp[i-1][tmp])%mod;
}
}
}
if(b == sum){
printf("%d\n", (dp[n][a]+1)%mod);
}
else{
printf("%d\n", dp[n][a]);
}
}
else{
int ans = 0;
if(a==sum){
ans++;
}
if(b==sum){
ans++;
}
printf("%d\n", ans);
}
}
return 0;
}