Processing math: 0%

2015年5月17日 星期日

[CF 509C] Sums of Digits

作法:

首先可以把問題化簡成:給定一個數S和一個正整數n,求出數字和為恰為S且比n大的最小正整數是多少。考慮將所求的數字和n從最高位開始往下比,找到第一位兩個數不同的位置,假設為 i ,那麼就代表在第 i 位之前所求的數字和n對應的位置都是一樣的,至於第i位和他之後要怎麼放,假設S扣掉第1位到第i-1位的值後剩下的值為S2,那麼就代表第i位以後一直到個位數的總和要恰好是S2,並且還得滿足第i位的值\geq n 的第 i 位的值 +1 ,當然還有第i位以後的數都要介於09之間,因此就可以先列出一個關於S2的不等式,不管S2太大或是太小都沒辦法在剩下的位子裡面放完需要的數字總和的數。具體來說,假設n的第i位的值為x,並且第i+1位一直到個位還有y個位子,那麼S2就必須滿足x+1 \leq S2 \leq 9\cdot (y+1)。並且剩下的問題不難得知只要往個位數的方向放儘量多的9就可以了,也就是從個位數開始往左一直放9,直到S2被用完為止,但記得要注意到如果S2太大,也有可能最後要加到第i位身上,畢竟他最大還是可以到9,不一定只能放x+1。最後只要注意到,當兩個數的第一個不一樣的位置越靠近個位的話,算出來的新的值就會越小,所以只要從小到大枚舉i,一找到一個解就趕快回傳就可以了。

code :



#include<bits/stdc++.h>
using namespace std;
const int maxn=500+10 ;
 
void print(const string &s)
{
    for(int i=0,j=0;i<maxn;i++) if(s[i]!='0'||j)
        printf("%c",s[i]) , j=1 ;
    printf("\n") ;
}
 
int s0[maxn] ;
inline int gets(int x,int y){return x?s0[y]-s0[x-1]:s0[y] ;}
string solve(string &s,int S)
{
    reverse(s.begin(),s.end()) ;
    for(int i=0;i<maxn;i++) s0[i]=i?s0[i-1]+s[i]-'0':s[i]-'0' ;
    for(int i=0;;i++)
    {
        if(s[i]=='9') continue ;
        if(gets(i,maxn-1)+1>S || gets(i,maxn-1)+9-(s[i]-'0')+9*i<S)
            continue ;
 
        int las=S-(gets(i,maxn-1)+1) ;
        string t ; t.resize(maxn) ;
        for(int j=0;j<maxn;j++) t[j]=(j>=i?s[j]:'0') ;
        t[i]++ ;
        for(int j=0;j<i && las;j++) t[j]=min(9,las)+'0' , las-=min(9,las) ;
        while(las--) t[i]++ ;
        reverse(t.begin(),t.end()) ;
        return t ;
    }
}
 
string s ;
main()
{
    int n ; scanf("%d",&n) ;
    s.resize(maxn) ;
    for(int i=0;i<maxn;i++) s[i]='0' ;
    while(n--)
    {
        int S ; scanf("%d",&S) ;
        s=solve(s,S) ;
        print(s) ;
    }
}
 

沒有留言:

張貼留言