題目連接:https://codeforces.com/contest/670/problem/Fios
題意:c++
有一個非負整數 $n$,在它的右側添上它的位數後,被髮送出去;例如 $6510$,加上位數 $4$,變成 $65104$,發送出去。git
可是,接受者接收到的數字則是被打亂了的,例如接收到了 $01465$,發送者只知道其中一段數字是什麼,例如知道原數字中有一段是 $51$。spa
要你根據已知的信息推測出可能的 $n$ 中最小的那個。code
題解:blog
首先在大約 $O(n)$ 的時間複雜度下能夠知道這個數字是 $k$ 位。ci
而後,咱們能夠知道這個數字是由 $c_0$ 個 $0$、$c_1$ 個 $1$、……、$c_9$ 個 $9$,以及一段給定的一段數字 $t$ 組成的。get
咱們要考慮如何找出最小的那個,不妨考慮以下可能的狀況:string
一、$t$ + $c_0$ 個 $0$ + …… + $c_9$ 個 $9$。it
二、在 $1 \sim 9$ 找一個最小的打頭,剩下的依舊按照若干個 $0$ + …… + 若干個 $9$ 排列,其中 $t$ 按照 $t[0]$ 是什麼,插在那個數的左側或者右側;例如 $10022599$,而 $t = [223]$,則有多是答案的是 $100[223]22599$ 或者 $10022[223]599$;另外一種例子是 $1089$,$t = [63]$,則多是答案的是 $10[63]89$。
答案只多是以上這些狀況中的一種。
AC代碼:
#include<bits/stdc++.h> using namespace std; const int SIZE=1e6+10; char s[SIZE],t[SIZE]; int slen,tlen; int cnt_s[10],cnt_t[10]; int digit() { int dgt; vector<int> v; for(dgt=tlen;dgt<=slen;dgt++) { int tp[10]={0}, k=dgt; while(k) ++tp[k%10], k/=10; bool ok=1; for(int i=0;i<10;i++) if(cnt_t[i]+tp[i]>cnt_s[i]) ok=0; int sum=0; for(int i=0;i<10;i++) sum+=cnt_s[i]-tp[i]; if(sum!=dgt) ok=0; if(ok) { for(int i=0;i<10;i++) cnt_s[i]-=cnt_t[i]+tp[i]; return dgt; } } } bool check(const string& s) //檢查前導零 { if(s.size()>1 && s[0]=='0') return 1; else return 0; } int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>s>>t; slen=strlen(s), tlen=strlen(t); for(int i=0;i<slen;i++) cnt_s[s[i]-'0']++; for(int i=0;i<tlen;i++) cnt_t[t[i]-'0']++; int dgt=digit(); string res1,res2,res3; res1=t; for(int i=0;i<10;i++) { for(int j=1;j<=cnt_s[i];j++) { res1+=(char)('0'+i); } } for(int i=1;i<10;i++) { if(cnt_s[i]>0) { res2+=(char)('0'+i); res3+=(char)('0'+i); cnt_s[i]--; break; } } for(int i=0;i<10;i++) { if(t[0]-'0'==i) res2+=(string)t; while(cnt_s[i]>0) { res2+=(char)('0'+i); res3+=(char)('0'+i); cnt_s[i]--; } if(t[0]-'0'==i) res3+=(string)t; } string ans; if(!check(res1)) ans=(ans.size()?min(ans,res1):res1); if(!check(res2)) ans=(ans.size()?min(ans,res2):res2); if(!check(res3)) ans=(ans.size()?min(ans,res3):res3); cout<<ans<<'\n'; }