Eは本番で法則を求めきれず、Editorialを見て解いた。
http://codeforces.com/contest/271/problem/E
問題
2つの整数値を持つ(a,b)というカードが複数あるとき、以下の処理により新たなカードを生成できる。
- (a,b)から(a+1,b+1)を生成
- a,bがともに偶数なら、(a,b)から(a/2,b/2)を生成
- (a,b)と(b,c)から(a,c)を生成
ここで、(1,a[1])、(1,a[2])、、、(1,a[N])のN毎のカードと数値Mが与えられたとき、そこから生成可能な1<=x
解法
本番では、元カードから生成できるカードのパターンを考えきれず時間切れ。
いかはEditorialの要約。
(x,y)において、差のy-x=dが奇数であるとする。(差が偶数なら、パターン1,2により差分を半分にできるので、いずれ差を奇数に持っていくことができる。)
とすると、(x,x+d)から(1,1+d)を生成し、そこからパターン1,3を使って(1,1+k*d)を生成できる。
また、ここから差がd,2d,4d,8d...となる任意の(x,y)を生成できる。
よって、(a[1]-1)~(a[N]-1)において、まず偶数要素は値が奇数になるまで2で割る。
次に、各要素の最大公約数Gを求める。
後は、Gの約数である各数値Dにおいて、(M-(2^L)D)を足しこんでいけばよい((x,y)のうち差がD,2D,4D,8D,...となるものを足しこむ)
int N,M; vector<int> A; ll gcd(ll a, ll b) { return (b==0)?a:gcd(b,a%b);} void solve() { int f,r,i,j,k,l; double ss; int x,y,d; N=GETi(); M=GETi(); FOR(i,N) { j=GETi()-1; while(j%2==0) j>>=1; A.push_back(j); } ll g=A[0]; for(i=1;i<A.size();i++) g = gcd(g,A[i]); ll sum=0; for(d=1;d*d<=g;d+=2) { if(g%d) continue; int cd=d; while(cd<=M) { sum += M-cd; cd<<=1; } if(d*d<g){ cd=g/d; while(cd<=M) { sum += M-cd; cd<<=1; } } } _P("%lld\n",sum); return; }
まとめ
理屈としてはわかるけど、これ本番中に思いつくの難しいよな…。
と思いつつ、非正規参加者も含めると40名以上は思いついてるんだよな…。