URAL 1658 Sum of Digits (DP) #by Plato

URAL 1658  Sum of Digits (DP) #by Plato

http://acm.timus.ru/problem.aspx?space=1&num=1658

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=20662#problem/B

 

题意: 已知一个长度<= 100的数,每位之和为s1,每位的平方和 为 s2,求这个数(多个答案输出最小的)

 

解法: f[i][j] 代表 每位和为i,平方和为j的最短长度。

f[i][j] = min{f[i – k][j – k*k]}

 

还算简单的DP吧,但是自己在其他地方犯了些错,当时就没有好的想法。

 

1. 第一次审题失误,看题时s1,s2 <= 10000,然后就觉得数据的范围是10^8,尝试了却也无从下手。

    事实上,数据有效范围是:900*8100,这个复杂度在时间和空间上就都可以接受了。

2. 然后DP方程确定了,开始去写。WA了几次:判定“No solution”的条件没写全,

    漏了f[s1][s2] > 100,还漏了 s1,s2超出有效范围的判定。

3. TLE,这也不得不说是个失误。

    开始的时候,是每个case都DP一次,范围是s1,s2,两个错误:s1,s2在有效范围的DP才有用;直接在900*8100范围DP只需要一次就OK了。

    不知道怎么得脑袋没转过来,两个问题查了有这么就都一直没有发现,后面对比别人的代码才发现,发现自己的代码小数据比它快很多,大数据却又慢很多。

#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <algorithm>
#define OP(s) cout<<#s<<"="<<s<<" ";
#define TP(i,j,k) cout<<#i<<"="<<i<<" "<<#j<<"="<<j<<" "<<#k<<"="<<k<<endl;
#define PP(s) cout<<#s<<"="<<s<<endl;
using namespace std;
int ans[200];
int choice[910][8110];

void find(int s1,int s2,int index)
{
    if (!index) return;
    int tmp = choice[s1][s2];
    ans[index] = tmp;
    find(s1 - tmp,s2 - tmp*tmp,--index);
}

int main()
{
    freopen("test.txt","r",stdin);
    int dig2[10];
    for (int i = 0; i < 10; i++) dig2[i] = i*i;


    static int f[910][8110];
    for (int i = 0;i < 910;i++) for (int j = 0;j < 8110;j++) f[i][j] = 1<<29;
    f[0][0] = 0;
    for (int i = 1; i <= 900; i++)
        for (int j = 1; j <= 8100; j++)
        {
            for (int k = 1; k <= 9; k++)
            {
                //if (i < k || j < dig2[k]) break;
                int tmp;
                //int tmp = f[i-k][j - dig2[k]] +1;
                //if (tmp > 100) continue;
                if (i >= k && j >= dig2[k] && (tmp = f[i-k][j - dig2[k]] +1) < f[i][j])
                {
                    f[i][j] = tmp;
                    choice[i][j] = k;
                }

            }
        }

    int T;
    scanf("%d",&T);
    while(T--)
    {
        int s1,s2;
        scanf("%d%d",&s1,&s2);

        int sa;
        if (s1 > 900 || s2 > 8100 || (sa = f[s1][s2]) > 100)
        {
            printf("No solution\n");
            continue;
        }

        find(s1,s2,sa);
        sort(ans+1,ans+sa+1);
        for (int i = 1; i <= sa; i++) printf("%d",ans[i]);
        printf("\n");
    }

    return 0;
}
/*
1. 第一次审题失误,看题时s1,s2 <= 10000,然后就觉得数据的范围是10^8,尝试了却也无从下手。
    事实上,数据有效范围是:900*8100,这个复杂度在时间和空间上就都可以接受了。
2. 然后DP方程确定了,开始去写。WA了几次:判定“No solution”的条件没写全,
    漏了f[s1][s2] > 100,还漏了 s1,s2超出有效范围的判定。
3. TLE,这也不得不说是个失误。
    开始的时候,是每个case都DP一次,范围是s1,s2,两个错误:s1,s2在有效范围的DP才有用;直接在900*8100范围DP只需要一次就OK了。
    不知道怎么得脑袋没转过来,两个问题查了有这么就都一直没有发现,后面对比别人的代码才发现,发现自己的代码小数据比它快很多,大数据却又慢很多。
*/



 

你可能感兴趣的:(URAL 1658 Sum of Digits (DP) #by Plato)