題意:給定一堆2二進制砝碼,給定一個物品,要求在天平兩端加入物品和砝碼使之平衡,求可能數。ios
思路:一開始想到了直接用數學原理,結果沒證出來。作以下思考,此題須要用二進制:spa
(1)設物品重量爲w,加入的砝碼重量爲x,另外一邊重量爲y,便有w+x=y。code
(2)另外,假如物品爲100110,加入的砝碼能夠爲000010,那麼總和爲101000,顯然x與y不能有位數相同的1(由於每種砝碼只有一個),所以便有x&y=0blog
依據這兩點,能夠知道此題的關鍵之處就在於如何分析w+x的進位狀況。分析物品的第i位,好比爲1,那麼若是前面的一位沒有進位,那麼他即可以加上1或者不加;若是進位,那就確定不能加1(由於加1之後與進位的1加上這一位的結果仍是1,與x&y=0矛盾),因此對於每一位,它的進位與不進位狀況須要分開判斷。get
DP思路:設f[i][0]表示判斷到i位時它不進位的狀況數,f[i][1]表示到i位時它進位的狀況數,都是從低位到高位判斷。數學
(1)先考慮f[i][0](不進位的狀況)string
(2)再考慮f[i][1](進位的狀況)it
這樣,DP方程就獲得了io
if(s[i] == 1){ f[i][0] = f[i-1][0]; f[i][1] = f[i-1][0]+f[i-1][1]; } else{ f[i][0] = f[i-1][0]+f[i-1][1]; f[i][1] = f[i-1][1]; }
注意:不得不說,這個題目挺不錯的,此題中間結果可能會超出long long,所以須要分次數判斷,由於這個點我WA了N次class
#include <iostream> #include <string> #include <cstring> #include <cstdio> #include <algorithm> #include <memory> #include <cmath> #include <bitset> #include <queue> #include <vector> #include <stack> using namespace std; #define CLR(x,y) memset(x,y,sizeof(x)) #define MIN(m,v) (m)<(v)?(m):(v) #define MAX(m,v) (m)>(v)?(m):(v) #define ABS(x) ((x)>0?(x):-(x)) #define rep(i,x,y) for(i=x;i<y;++i) const int MAXN = 1100000; int t,n,m,d; int s[MAXN]; int dp[MAXN][2]; void Solve() { char c; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&d); getchar(); CLR(s,0); for(int i = m-1; i >= 0; --i){ scanf("%c",&c); s[i] = c-'0'; } if(s[0] == 0) { dp[0][0] = 1; dp[0][1] = 0; } else{ dp[0][0] = 1; dp[0][1] = 1; } for(int i = 1; i < n; ++i){ if(s[i] == 1){ dp[i][0] = dp[i-1][0]; dp[i][1] = dp[i-1][0]+dp[i-1][1]; } else{ dp[i][0] = dp[i-1][0]+dp[i-1][1]; dp[i][1] = dp[i-1][1]; } if(dp[i][0]>=d) dp[i][0]-=d; if(dp[i][1]>=d) dp[i][1]-=d; } cout<<(dp[n-1][0])<<endl; } } int main() { Solve(); return 0; }