您的位置:首页 > 其它

Timus Online Judge 1658 Sum of Digits

2015-10-31 11:18 218 查看
这道题做了快24个小时(昨天十一点做到今天十一点),一直不知道为什么会WA在第四组,而且WA了12次,突然AC,感觉幸福来得太突然。

题目大意:是否存在数N,使得N上的每一位相加得s1,每一位的平方相加得s2?如果存在输出最小的数N,不存在则输出"No solution",如果最小的数N大于100位也要输出“No solution”。其中,s1和s2的范围在0~10000之间。

首先来复习一下一个数学知识:有没有不相等的四个正整数,使得a^2 + b^2 = c^2 + d^2  和 a + b = c + d同时成立。两个式子变下型,(a + c) * (a - c) = (d + b) * (d - b), a - c = d - b。那么得出a + c = d + b, 再联立a - c = d - b, 可以得出 a = d, b = c。

所以,根本找不到这样的四个数,那么我们就可以放心了。基于这一点,我们就可以看出,在N的位数确定为K的情况下,s1 和 s2所对应的N中所包含的k个数就都已经确定了,只需要按照升序排好,它就是这么多位中最小的数。

其实dp方程真的不会太难,我的dp[i][j]是表示的各位的和为i且各位的平方的和为j的数中,最小的数的位数,那么dp[i + k][j + k * k] = min{dp[i][j] + 1}。然后记录一下dp[i][j]到dp[i + k][j + k * k]是选的数字几,也就是保存一下k,保存一下路径就OK了。

其实,分析这道题目和其它的许多题目类似, 都是从时间复杂度和空间复杂度入手,先想想怎么才能不会TLE、MLE,这样才能找到正确的解题思路,千万不能纠结。

代码甚是丑陋,请多指教!

#include <iostream>
#include <algorithm>
#define pii pair<int, int>
#define x first
#define y second
using namespace std;
int dp[901][8101], path[901][8101];
void Init() {
for (int i = 0; i <= 900; ++i) {
for (int j = 0; j <= 8100; ++j) {
dp[i][j] = 101;
}
}
dp[0][0] = 0;//初始化,由dp[0][0]推到dp[1][1]、dp[2][4]、dp[3][9]、dp[4][16]……
for (int i = 0; i <= 900; ++i) {
for (int j = i; j <= 8100; ++j) {
for (int k = 1; k <= 9; ++k) {//或许会枚举出一些重复的情况,但是如果从path[i][j]的值开始枚举的话也许会漏掉一些解,之前就在这里一直WA
if (i + k > 900 || j + k * k > 8100) continue;
if (dp[i + k][j + k * k] > dp[i][j]) {
dp[i + k][j + k * k] = dp[i][j] + 1;
path[i + k][j + k * k] = k;//更新的时候记得保存路径
}
}
}
}
}
int main() {
Init();
int T;
cin >> T;
for (int I = 1; I <= T; ++I) {
int s1, s2;
cin >> s1 >> s2;
if (s1 > 900 || s2 > 8100 || s1 > s2 || dp[s1][s2] > 100) cout << "No solution" << endl;
else {
string ans;
pii p(s1, s2);
while (p.x && p.y) {//路径还原
int t = path[p.x][p.y];
p.x -= t, p.y -= t * t;
ans += t + '0';
}
sort(ans.begin(), ans.end());
cout << ans << endl;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: