题意:首先告诉你一个东西叫数位根,就是把这个数每一位加起来得到一个数,如果不是1到9就再把得到的数每一位加起来,直到变成1到9。然后现在有N个1到9的数,另外给两个1到9的数A和B,让你把这N个数分成两组,问有多少方案使其中一组的和的数位根为A,另一组为B,所有数的数位根为A或B也算到方案总数里面。
我是用DP做的,一开始定义dp[i][a][b]为把前i个数分两组,第一个数所在那组得到的数位根是A,另一组得到的数位根是B,不过这样是会超时的。
后来队友发现了个性质就是前i个数的和是已经确定的,假如分成两组,一组的数位根确定下来之后另一组的数位根是唯一对应的,那么就可以把后面一维给省掉了。
定义get函数为获取数位根,那么转移就是:
dp[i][get(j+num[i])]+=dp[i-1][j];
dp[i][j]+=dp[i-1][j];
dp[i][get(sum[i-1])]+=1;(前i-1个数一组,第i个数单独一组)
我还用了滚动数组实现,不过好像没什么必要。
至于题解说的直接模9完全没有发现,而且当时手残get函数还出了点小bug浪费了很多时间,不过一发就过了,过了就好吧。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<list>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define mod 258280327
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)>(b)?(b):(a))
//const int MAXN = ;
LL dp[2][12];
int now,last;
int n,A,B;
int num[100010];
int sum[100010];
int pre[100010];
int get(int x)
{
if(x<=0)return 0;
int ret=x;
while(ret==0||ret>9)
{
x=ret;
ret=0;
while(x)
{
ret+=x%10;
x/=10;
}
}
return ret;
}
int main()
{
//#define LOCAL
#ifdef LOCAL
freopen("e:\\read.txt","r",stdin);
//freopen("e:\\write.txt","w",stdout);
#endif
int T;
cin>>T;
while(T--)
{
scanf("%d%d%d",&n,&A,&B);
rep(i,1,n)
{
scanf("%d",&num[i]);
sum[i]=sum[i-1]+num[i];
pre[i]=get(sum[i]);
}
LL ans=0;
if(get(sum[n])==A)ans++;
if(get(sum[n])==B)ans++;
clr(dp,0);
dp[0][num[1]]=1;
last=1;
now=0;
int t1,t2;
rep(i,3,n)
{
last=now;
now^=1;
clr(dp[now],0);
rep(j,1,9)if(dp[last][j])
{
t1=get(j+num[i]);
dp[now][t1]=(dp[now][t1]+dp[last][j])%mod;
dp[now][j]=(dp[now][j]+dp[last][j])%mod;
}
dp[now][pre[i-1]]=(dp[now][pre[i-1]]+1)%mod;
}
if(get(sum[n]-A)==B)ans=(ans+dp[now][A])%mod;
if(get(sum[n]-B)==A)ans=(ans+dp[now][B])%mod;
cout<<ans<<endl;
}
return 0;
}