题目链接: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;
}