1. 程式人生 > >Codeforces Gym 100531D Digits (暴力、打表)

Codeforces Gym 100531D Digits (暴力、打表)

這裡寫圖片描述
題目連結
1.暴力打表。。。
上來隊友開始推規律

n
1 1= 1
2 11= 1 + 10
3 33= 2 + 11 + 20
4 66= 3 + 12 + 21 + 30
5 110= 4 + 13 + 22 + 31 + 40
6 165= 5 + 14 + 23 + 32 + 41 + 50
7 231= 6 + 15 + 24 + 33 + 42 + 51 + 60
8 308= 7 + 16 + 25 + 34 + 43 + 52 + 61 + 70
9 396= 8 + 17 + 26 + 35 + 44 + 53 + 62 + 71 + 80
10 495= 9 + 18 + 27 + 36 + 45 + 54 + 63 + 72 + 81 + 90
11 603= 9 + 18 + 27 + 36 + 45 + 54 + 63 + 72 + 81 + 90 + 108
12 720= 9 + 18 + 27 + 36 + 45 + 54 + 63 + 72 + 81 + 90 + 108 + 117
推到這裡,隊友說之後的只能是各位數字之和為9的數加起來和最小

於是我簡單的打了個表

int cnt=0;
ll  sum=0;
for(int i=1; i<=10000000; i++)
{
    if(getsum(i) == 9)  //getsum()是求各位數字之和
    {
         sum+=i;
         cnt++;
         book[cnt] = sum;
    }
    if(cnt == 5000) break;
}

如此暴力的把n=10以後的答案都算出來了。。
結果WA在了第八組上
我開始debug。。。一直覺得題面給的除以9是個暗示。。。
所以改了挺長時間也沒出,直到我覺得需要試一下各位數之和等於別的情況修改getsum(i) == 15 book[5000]小了很多
當getsum(i)==10 book[39] 就比 個位數字之和等於9的book[39]小

所以我有了個大膽的想法= = 我試了一些數 發現當getsum(i)==20 時
或者再往後 它的book[5000]開始不再變小,開始穩定不變。
程式碼就出來了
。。。略微暴力
最壞的求各位數字之和是分解十次 所以最壞的時間複雜度是10^8次冪吧
但是由於有剪枝和大多數數字到不了十位,所以還是會好很多。

#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
ll book[5005];
ll getsum(int
x) { int sum=0; while(x) { sum+=x%10; x = x/10; } return sum; } int main() { int n; for(int k=9; k<=20; k++) { int cnt=0; ll sum=0; for(int i=1; i<=10000000; i++) { if(getsum(i) == k) { sum+=i; cnt++; if(k==9) book[cnt] = sum; else book[cnt] = min(book[cnt],sum); } if(cnt == 5000) break; } } book[1] = 1; book[2] = 11; book[3] = 33; book[4] = 66; book[5] = 110; book[6] = 165; book[7] = 231; book[8] = 308; book[9] = 396; book[10] = 495; //freopen("digits.in", "r", stdin); //freopen("digits.out", "w", stdout); while(cin>>n) { printf("%lld\n",book[n]); } return 0; }

2.來自大牛們的科學暴力法:
來源部落格

這個的思路就是存下 在1到100000中 每種各位數字之和的出現次數,並在結構體中存下這個各位數字之和的最小和 。
然後輸入n 匹配次數。 他在測試中得到正確答案也一定是測試了很多範圍最終確定100000

    /********************************************************  
    題意:給你一個n表示需要你找n個數字,每個數字的各個位數之 
    和必須相等,求最小的n個數字之和 
    型別:暴力  
    分析:因為n個數字都必須是正整數,由n<=5000, 暴力測試發現 
    1~100000以內可以得到5000個正解,由1~100000每個數字最大分 
    解次數<=10,暴力解決這道題的複雜度<10^6 
    *********************************************************/    
    #include<stdio.h>  
    #include<algorithm>  
    #include<iostream>  
    #include<cmath>  
    #include<cstring>  
    using namespace std;  
    struct node{  
        long long sum;  
        int cishu;  
    }a[100];  
    int main(){  
        //freopen("digits.in","r",stdin);  
        //freopen("digits.out","w",stdout);  
        int n;  
        scanf("%d",&n);  
        long long b=0xfffffff;  
        for(int i=1;i<=100000;i++){  
            int tmp=i;  
            int summ=0;  
            while(tmp){  
                summ+=tmp%10;  
                tmp/=10;  
            }  
            a[summ].cishu++;  
            a[summ].sum+=i;  
            if(a[summ].cishu==n){  
                if(a[summ].sum<b)b=a[summ].sum;  
            }  
        }  
        cout<<b<<endl;  
    }