题目描述:
有一个物品重量为 w w w,现在你有 1 , 2 , 4 , … , 2 n 1,2,4,…,2^n 1,2,4,…,2n重量的砝码,问有多少种方法可以使得天平平衡。 w w w以二进制给出。
分析:
- 根据题目的意思,可以分析出2个重要的信息,假设在 w w w方托盘放上 x x x质量的砝码,在天平的另一边放上总共 y y y质量的砝码,则有等式 x + w = y x+w=y x+w=y。
- 另外,因为每一种砝码只有一个,且每一个砝码都是
2
2
2的整次幂,化成
2
2
2进制后只有最高位为
1
1
1,而其余位为
0
0
0,因此又有以下等式成立:
x
&
y
=
0
x \& y = 0
x&y=0。
综上所述,我们需要求解以下方程组的合法正整数解的个数:
{ x + w = y x & y = 0 \begin{cases} x +w = y \\ x \& y = 0 \end{cases} {x+w=yx&y=0
考虑数位 d p dp dp。
设 f i , 0 f_{i,0} fi,0表示判断到i位时它不进位的情况数, f i , 1 f_{i,1} fi,1表示到i位时它进位的情况数,从低位到高位判断。
分类讨论:
( 1 1 1) 先考虑 f i , 0 f_{i,0} fi,0的情况(即不进位的情况):
- 1. 1. 1. 当 w w w的第 i i i位为 1 1 1时,如果前面不进位,那么这一位只能加上 0 0 0才满足不进位的情况;如果前面进位,那么无论如何不可能使这一位不进位,因此有方程 f i , 0 = f i − 1 , 0 f_{i,0}=f_{i-1,0} fi,0=fi−1,0成立;
- 2. 2. 2. 当 w w w的第 i i i位为 0 0 0时,如果前面不进位,那么这一位只能选择 0 0 0(因为选择加 1 1 1的话将会与条件 x & y = 0 x\&y=0 x&y=0矛盾);如果前面进位,那么这一位也只能选择 0 0 0才能使 i i i位也不进位,因此有方程 f i , 0 = f i − 1 , 0 + f i − 1 , 1 f_{i,0}=f_{i-1,0}+f_{i-1,1} fi,0=fi−1,0+fi−1,1成立;
( 2 2 2) 再考虑 f i , 1 f_{i,1} fi,1的情况(即进位的情况):
- 当 w w w的第 i i i位为 1 1 1时,如果前面不进位,那么这一位只能选择1才能使i位进位;如果前面进位,那么只能选择 0 0 0使之进位(如果选择 1 1 1那么结果将会与条件 x & y = 0 x\&y=0 x&y=0矛盾),因此有方程 f i , 1 = f i − 1 , 0 + f i − 1 , 1 f_{i,1}=f_{i-1,0}+f_{i-1,1} fi,1=fi−1,0+fi−1,1成立;
- 当 w w w的第 i i i位为 0 0 0时,如果前面不进位,那么这一位无论如何不可能进位;如果前面进位,那么只能选择 1 1 1才能使i位进位,因此有方程 f i , 1 = f i − 1 , 1 f_{i,1}=f_{i-1,1} fi,1=fi−1,1成立;
D
p
Dp
Dp方程转移到此结束.
程序初始化与上述分析类似.
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000001;
int n, m, Mod = 0;
int a[N] = {};
int f[N][2] = {};
int main() {
int T;
scanf("%d",&T);
while (T --) {
memset(a, 0, sizeof(a));
memset(f, 0, sizeof(f));
scanf("%d%d%d",&m,&n,&Mod);
char ch;
ch = getchar();
for (int i=n-1;i>=0;i--) {
ch = getchar();
a[i] = ch - '0';
}
// for (int i=0;i<=n-1;i++) cout<<a[i]<<' ';
if (a[0] == 0) {
f[0][0] = 1, f[0][1] = 0;
}
else {
f[0][0] = f[0][1] = 1;
}
for (int i=1;i<=m;i++) {
if (a[i] == 0) {
f[i][0] = f[i-1][0] + f[i-1][1];
f[i][1] = f[i-1][1];
}
else {
f[i][0] = f[i-1][0];
f[i][1] = f[i-1][0] + f[i-1][1];
}
f[i][0] = f[i][0] % Mod, f[i][1] = f[i][1] % Mod;
}
printf("%d\n",f[m-1][0]);
}
}