已知一个数字中某些位数被模糊,同时这个数能够被k整除,那么这个数有多少种可能?简单的方法就是用dp来统计所有的状态,注意状态的表示是用余数来表示的。状态转移的时候统计一下数量就好。
#include "iostream"
#include "vector"
#include "algorithm"
#include "string"
#include "cmath"
using namespace std;
int main(void){
int n;
string k;
while (cin >> k)
{
cin >> n;
int num = k.size();
int count = 0;
long long sum = 0;
int usum = 0;
long long unknown[20] = { 0 };
for (int i = 0; i < num; ++i)
{
if (k[i] == 'X')
{
count += 1;
unknown[num - i - 1] = pow(10, num - i - 1);
sum *= 10;
}
else
sum = sum * 10 + k[i] - '0';
}
vector<long long> dp(n, 0);
dp[0] = 1;
int c = (n - sum%n) % n;
for (int i = 0; i < num; ++i)
{
if (unknown[i] == 0)
continue;
vector<long long> tmpdp(n, 0);
for (int s = n - 1; s >= 0; --s)
{
if (dp[s])
{
for (int j = 0; j < 10; ++j)
tmpdp[(s + unknown[i] * j) % n] += dp[s];
}
}
dp = tmpdp;
}
cout << dp[c] << endl;
}
return 0;
}
有n个砖头,用这些砖头构建两个相同高度的最高的塔?不一定全部用完这些砖头。这道题可暴力加剪枝(其实我很奇怪暴力居然可以过),或者dp解决,告诉你输出不超过50w,所以状态可以写成dp[d],d代表两个塔的高度只差,dp[d]代表其中的最大高度。这样写的好处就在于用状态自己的值也作为状态的一部分,否则状态表示成dp[left][right]那么数量就爆炸了。
#include "iostream"
#include "vector"
#include"algorithm"
#include "cmath"
using namespace std;
int main() {
int n = 0;
while (cin >> n){
vector<int> a(n);
int sum = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
sum += a[i];
}
sum = min(sum, 500000);
vector<int> dp(sum + 1, -1);
dp[0] = 0;
dp[a[0]] = a[0];
for (int i = 1; i < n; ++i) {
vector<int> tmp(dp);
int h = a[i];
for (int j = 0; j <= sum; ++j) {
if (j + h <= sum && dp[j + h] != -1)
tmp[j] = max(tmp[j], dp[j+h]);
if (j - h >= 0 && dp[j - h] != -1)
tmp[j] = max(tmp[j], dp[j - h] + h);
else if (j - h < 0 && dp[h - j] != -1)
tmp[j] = max(tmp[j], dp[h-j]+j);
}
dp = tmp;
}
cout << (dp[0]==0 ? -1:dp[0] )<< endl;
}
return 0;
}