题目描述:
有一个物品重量为www,现在你有1,2,4,…,2n1,2,4,…,2^n1,2,4,…,2n重量的砝码,问有多少种方法可以使得天平平衡。www以二进制给出。
分析:
- 根据题目的意思,可以分析出2个重要的信息,假设在www方托盘放上xxx质量的砝码,在天平的另一边放上总共yyy质量的砝码,则有等式x+w=yx+w=yx+w=y。
- 另外,因为每一种砝码只有一个,且每一个砝码都是222的整次幂,化成222进制后只有最高位为111,而其余位为000,因此又有以下等式成立: x&y=0x \& y = 0x&y=0。
综上所述,我们需要求解以下方程组的合法正整数解的个数:
{x+w=yx&y=0\begin{cases} x +w = y \\ x \& y = 0 \end{cases}{x+w=yx&y=0
考虑数位dpdpdp。
设fi,0f_{i,0}fi,0表示判断到i位时它不进位的情况数,fi,1f_{i,1}fi,1表示到i位时它进位的情况数,从低位到高位判断。
分类讨论:
(111) 先考虑fi,0f_{i,0}fi,0的情况(即不进位的情况):
- 1.1.1. 当www的第iii位为111时,如果前面不进位,那么这一位只能加上000才满足不进位的情况;如果前面进位,那么无论如何不可能使这一位不进位,因此有方程fi,0=fi−1,0f_{i,0}=f_{i-1,0}fi,0=fi−1,0成立;
- 2.2.2. 当www的第iii位为000时,如果前面不进位,那么这一位只能选择000(因为选择加111的话将会与条件x&y=0x\&y=0x&y=0矛盾);如果前面进位,那么这一位也只能选择000才能使iii位也不进位,因此有方程fi,0=fi−1,0+fi−1,1f_{i,0}=f_{i-1,0}+f_{i-1,1}fi,0=fi−1,0+fi−1,1成立;
(222) 再考虑fi,1f_{i,1}fi,1的情况(即进位的情况):
- 当www的第iii位为111时,如果前面不进位,那么这一位只能选择1才能使i位进位;如果前面进位,那么只能选择000使之进位(如果选择111那么结果将会与条件x&y=0x\&y=0x&y=0矛盾),因此有方程fi,1=fi−1,0+fi−1,1f_{i,1}=f_{i-1,0}+f_{i-1,1}fi,1=fi−1,0+fi−1,1成立;
- 当www的第iii位为000时,如果前面不进位,那么这一位无论如何不可能进位;如果前面进位,那么只能选择111才能使i位进位,因此有方程fi,1=fi−1,1f_{i,1}=f_{i-1,1}fi,1=fi−1,1成立;
DpDpDp方程转移到此结束.
程序初始化与上述分析类似.
代码如下:
#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]);
}
}

本文探讨了给定物品重量和一系列2的整次幂砝码时,如何通过数位DP算法计算天平平衡的方法数量。分析了在特定条件下砝码放置的合法正整数解,并详细解释了DP状态转移方程。
988

被折叠的 条评论
为什么被折叠?



