题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5389
大体题意是:有两个门A和B,还有一群人,每个人都有一个数字,
疯了一样的T。。比赛的时候十连T也是醉醉的。
这道题感觉像DP,但是不知道从何下手,看别人敲出来才知道怎么去用。
在比赛过程中还有一个问题,想法对了,样例过了,但是T了
原因是因为数组开大了,在dp的过程中用了memset,导致T
在标程里,用了滚动数组,感觉很巧妙,因为dp只需要知道上一状态即可,
利用异或的性质,不断滚动0101010101
---------------------------------------关于digital的性质------------------------------------------------------------
当一群人各位数字之和等于门上数字的时候才可以通过门,可以只通过一个门也可以两个门都通过。
The digital root of a non-negative integer is the single digit value obtained by an iterative process of summing digits,
on each iteration using the result from the previous iteration to compute a digit sum. The process continues until
a single-digit number is reached.
关于digital root(以下用R表示),有以下几条性质:
1、9加(乘)任何数所得的和(积)的数字根,等于原数的数字根(9)
2、若A+B=C,则A,B的数字根(Ra Rb)的和的数字根为C的数字根(Rc)
3、若A*B=C,则A,B的数字根(Ra Rb)的积的数字根为C的数字根(Rc)
4、若A^n=B,则Ra^n的数字跟=Rb。
------------------DP思路---------------------
dp[i+1][a[i]+k] = dp[i+1][a[i]+k] + dp[i][k];
更新加了一个数之后的状态
dp[i+1][k] = dp[i+1][k] + dp[i][k];
加上上一状态的情况数
------------------分情况讨论-------------------
之后比较巧的是对于情况的讨论
1、如果数字跟不等于A+B且不等于A且不等于B,则情况数为0
2、如果是数字根等于A+B的数字根,那么情况数就等于dp[n][A] = dp[n][B]
3、如果数字根等于A或B,那么情况数只有一个
4、如果数字跟等于A且等于B,那么情况数有两个
具体代码如下
1 int ans=dp[now][A]*(((A+B)%9)==sum); 2 if(sum==A&&B!=0)ans=(ans+1)%MOD; 3 if(sum==B&&A!=0)ans=(ans+1)%MOD;
注意到后两种情况其实可以合并,如果A=B的话,后两个if语句同时成立,ans = 2;
1 #include<stdio.h> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,j,k) for(int i=(int)j;i<(int)k;i++) 5 #define per(i,j,k) for(int i=(int)j;i>(int)k;i--) 6 using namespace std; 7 const int MAXN = 1000000; 8 const int MOD = 258280327; 9 int T, n; 10 int A, B; 11 int a[MAXN]; 12 int now, sum, ans; 13 int dp[2][10]; 14 int main(){ 15 scanf("%d",&T); 16 while(T--){ 17 scanf("%d",&n); 18 scanf("%d %d",&A,&B); 19 A %= 9;B %= 9; 20 sum = 0; 21 rep(i,0,n){ 22 scanf("%d",&a[i]); 23 a[i] = a[i] % 9; 24 sum = (sum+a[i])%9; 25 } 26 if( sum != ((A+B)%9) && sum != A && sum != B){ 27 puts("0"); 28 continue; 29 } 30 memset(dp,0,sizeof(dp)); 31 dp[0][0] = 1; 32 now = 0; 33 rep(i,0,n){ 34 now ^= 1; 35 rep(k,0,9) dp[now][k] = 0; 36 rep(k,0,9){ 37 dp[now][(a[i]+k)%9] = ( dp[now][(a[i]+k)%9] + dp[now^1][k])%MOD; 38 dp[now][k] = ( dp[now][k] + dp[now^1][k])%MOD; 39 } 40 } 41 int ans=dp[now][A]*(((A+B)%9)==sum); 42 if(sum==A&&B!=0)ans=(ans+1)%MOD; 43 if(sum==B&&A!=0)ans=(ans+1)%MOD; 44 printf("%d\n",ans); 45 } 46 }