これまでの過去の★5を考えると、★4でもいい気はするなぁ…
http://yukicoder.me/problems/no/434
http://yukicoder.me/problems/no/435
問題
N桁の整数Sが与えられる。
この整数に対し、隣接する2桁の和を取り、(和が10以上の場合それが1桁になるまで上下桁の和を取ることを繰り返した上で)再び連結して一桁小さな数を作る、という処理を全体が1桁になるまで繰り返す。
最終的に得られる値は何か。
解法
ある数の各桁の総和を問題のように取るということは、元の整数のmod 9を取ったものに等しい。
ただし、S!=0である場合、mod 9を取った結果が0なら解は9とする。(S!=0なら結果が0になり得ないため)。
元のSの各桁が何回分最終的な解に寄与するかを考えると、パスカルの三角形状になっていることがわかる。
すると、求める解は (ただし%9の部分は剰余を取る対象の数が非0で9の倍数の場合、9とする)となる。
ここで問題は合成数で剰余を取るため、良くあるフェルマーの小定理を用いた高速なCombination計算ができないことである。
そこで、あきらめてCombinationにおける分子分母それぞれ素因数分解を行い、それを用いてCombinationを行おう。
その際、最終的に9の剰余を取るので、実際は(素因数%9)を掛けた数を覚えておけば、覚えるべき素因数の数は少なくて済む。
const int prime_max = 10000001; short divp[prime_max]; void cprime() { for(int i=2;i<prime_max;i++) if(divp[i]==0) { for(ll j=1LL*i*i;j>i&&j<prime_max;j+=i) divp[j]=i; } } ll modpow(ll a, ll n, ll mo) { ll r=1; while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1; return r; } int T; int N,X,A,B,M; int num[12]; void solve() { int i,j,k,l,r,x,y; string s; cprime(); cin>>T; while(T--) { cin>>N>>X>>A>>B>>M; ll ret=0; ZERO(num); for(i=0;i<N;i++) { if(num[3]<2) { x = 1; for(j=2;j<=8;j++) x = x*modpow(j,num[j],9); ret += x*(X%10); } else { ret += 9*(X%10); } if(i<N-1) { x = N-1-i; y = 1+i; while(divp[x]) num[divp[x]%9]++, x /= divp[x]; num[x%9]++; while(divp[y]) num[divp[y]%9]--, y /= divp[y]; num[y%9]--; } X = ((X^A)+B)%M; } while(ret>=10) ret=ret%10+ret/10; cout<<ret<<endl; } }
解法
数字根っていう言い方、初めて聞いた。