【NOIP2013模拟9.29】密码
Description
在又一次消滅林登·萬的戰斗中,指揮官moreD繳獲了一個神奇的盒子。盒子異常的堅固,以至于完全無法摧毀,唯一打開的方式是通過盒上的密碼鎖。
經過仔細的調查,研究人員一致認為這個盒子中隱藏了林登·萬和他的弟弟林登·圖的秘密。然而moreD使用了許多辦法,都沒能打開這個盒子。最后只好將這個盒子封存在了倉庫的底層。
事情并沒有結束。moreD之所以沒能打開這個盒子,是因為老牌的調查員/邪教徒LCJ隱瞞了它的調查結果。LCJ經過不懈的努力,得出了結論。即:給你一個長度不超過17的由0~9組成的無前導0的字符串S,S中的數字排列組成的無前導零的能被17整除的整數中字典序第K小的那個數就是密碼。
盡管解開了密碼,然而處于對未知的恐懼,LCJ最終并沒有打開盒子。然而另一個資歷較淺的調查員/邪教徒,你,YDMan不知通過什么辦法得知了上述信息,并得到了S和K。現在你決定要解開這個密碼,來取得“終極的智慧”。
Input
一行,一個由0~9組成的字符串S和一個不超過17!的正整數K。
Output
一行,即密碼。數據保證有解。
Sample Input
輸入1:
17 1
輸入2:
2242223 2
Sample Output
輸出1:
17
輸出2:
2242232
Data Constraint
對于40%的數據,字符串S長度<=12,K<=2*10^6。
對于100%的數據,字符串S長度<=17,K<=17!。
Hint
后記:
事實上,盒子中裝的正是倫道夫·卡特當年穿越銀匙之門的銀色鑰匙。YDMan在“掌(bei)握(xia)智(huai)慧(le)”智慧,終于成為了一個偉大的“詩(huan)人(zhe)”。而林登·萬則和和他的弟弟繼續使用林登·圖鑰匙與指揮官moreD進行不屈不撓的斗爭。
.
.
.
.
.
分析
對于40%的數據,按字典序從小到大搜索原串的每一個排列。同時開一個數組,G[n][S][k],表示前n位使用的數字集合為S,對17取模的結果為k的情況下,是否有合法的數字能被17整除。當搜索一個出現過的狀態,就可以直接用f判斷是否有解,來減去大部分無用狀態。
對于100%的數據,使用數位DP。F[n][S][k],表示前n位使用的數字集合為S,對17取模的結果為k的情況下,后續的位置數字排列的合法方案數。轉移可以用記憶化搜索實現。求解的過程只要從高位開始從小到大枚舉答案的每一位,判斷是否有足夠數目的解,即可。
由于以上的記搜打不對,超時,所以我用了狀壓dp
題目大意:給你一個由0~9組成的字符串,將其位置排序后選可以被17整除的字典序為k的數
設f[s][i]為選數字的狀態為s,取模后的余數為i的方案數
我們可以先將所有位數先排序
轉移方程就是f[i^(1<<(j-1))][(w+l[ j ]*q)%17]+=f[i][w]
i是枚舉的狀態,j是第j位(也就是第j個數),w就是枚舉的余數,q是后導零的個數
那么現在考慮如果有相同的數字,要除去重復的情況,也就是除以所有的數的f[z[j]]的乘積
z[j]就是j的個數
這樣就可以有效解決它的重復的方案數
如果求最終的答案呢?
答案要求字典序第k小的
那么我們可以從高位開始選,從小的開始加
如果現在在到第i位選j
那么方案數就是f[q|(1 < < i-1)][p+l[j]*y[n-i]]
q表示前面選的狀態,r表示前面選的方案數
對于當前一個f[q][p]
如果大于等于k,即它的方案數在當前選的狀態內,那么當前枚舉的數是有效的,直接輸出
如果小于等于k,將k減去當前狀態和余數的方案數
數位dp、狀壓dp
.
.
.
.
.
程序:
#include <iostream> #include <string.h> #include <algorithm> using namespace std; long long f[1<<17][17],l[18],x[18],y[18],k,len,z[18]; string s;int main() {cin>>s;cin>>k;len=s.length();for (int i=1;i<=len;i++) l[i]=s[i-1]-'0';sort(l+1,l+len+1);int g=(1<<len)-1;f[g][0]=1;for (int i=g;i>0;i--){int q=1;for (int j=1;j<=len;j++) if ((i&(1<<(j-1)))==0) q*=10,q%=17;for (int j=1;j<=len;j++)if (i&(1<<(j-1))){for (int w=0;w<=16;w++) f[i^(1<<(j-1))][(w+l[j]*q)%17]+=f[i][w];}}x[0]=1;for (int i=1;i<=17;i++) x[i]=x[i-1]*i;for (int i=g;i>0;i--){for (int j=0;j<=9;j++) z[j]=0;for (int j=1;j<=len;j++) if ((i&(1<<(j-1)))==0) z[l[j]]++;for (int j=0;j<=9;j++)for (int w=0;w<=16;w++)f[i][w]=f[i][w]/x[z[j]];}int p=0,q=0;y[0]=1;for (int i=1;i<=len;i++) y[i]=(y[i-1]*10)%17;for (int i=1;i<=len;i++){int bz=-1;for (int j=1;j<=len;j++)if ((q&(1<<(j-1)))==0){if (bz==l[j]) continue;bz=l[j];int w=(17-(p+l[j]*y[len-i])%17)%17;if (i==1&&l[j]==0) continue;if (f[q|1<<(j-1)][w]>=k){q|=1<<(j-1);(p+=l[j]*y[len-i])%17;cout<<l[j];break;} else k-=f[q|1<<(j-1)][w];}}for (int i=1;i<=len;i++) if (((q&1<<(i-1)))==0) cout<<l[i];return 0; }轉載于:https://www.cnblogs.com/YYC-0304/p/9499920.html
總結
以上是生活随笔為你收集整理的【NOIP2013模拟9.29】密码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【GDKOI2004】使命的召唤
- 下一篇: 【NOIP2013模拟9.29】TheS