TopCoder SRM 334 Div1 Medium ExtendedHappyNumbers
問題
Nに対してSk(N)を、
Σ(Nの各桁)^kと定義する。
Nに対して、Nの幸福度を、数列N,Sk(N),Sk(Sk(N)),...,の最小値とする。
与えられた整数A,Bに対して、
A≦i≦Bなるすべてのに対するiの幸福度の和を求めよ。
制約条件
A,B≦1000000
k≦6
方針
メモ化してiに対する幸福度を求める。
Sk(i)がループしたら、ループ部分の幸福度はループ部分の最小値となる。
ループの検出は、フラグをたてながら深さ優先探索をすればよい。
いままで訪問した数字をスタックに入れておいて、ループの部分の数字を書き換えるのに使う。
ソースコード
const int MX=4000000; int k,dp[MX]; int sz,st[MX]; bool v[MX]; int rec(int c){ if(v[c]){ int tmp=dp[c]; for(int i=sz-1;i>=0&&st[i]!=c;i--)tmp=min(tmp,st[i]); for(int i=sz-1;i>=0&&st[i]!=c;i--)dp[st[sz-1]]=tmp; return dp[c]=tmp; } if(dp[c]>=0)return dp[c]; v[c]=1; dp[c]=c; st[sz++]=c; int nxt=0; for(int m=c;m;m/=10){ int t=m%10, s=1; rep(i,k)s*=t; nxt+=s; } return dp[c]=min(dp[c],rec(nxt)); } class ExtendedHappyNumbers { public: long long calcTheSum(int A, int B, int K) { memset(dp,-1,sizeof(dp)); memset(v,0,sizeof(v)); k=K; ll ans=0; for(int i=A;i<=B;i++){ sz=0; ans+=rec(i); rep(j,sz)v[st[j]]=0; } return ans; } };