TopCoder SRM 333 Div1 Medium RepeatedPatterns
問題
'0'または'1'からなる文字列P1,P2が与えられる。
文字列S(n)を、P1を100万回繰り返した後、P2をn回繰り返した文字列とする。
文字列Sを、S(1)+S(2)+……と無限につなげたものとする。
文字列Tを、Sの先頭から10^16文字を取った文字列とする。
TにおいてゼロがzeroCount回連続して現れる最初の位置を求めよ。
現れない場合は-1を返せ。
制約条件
P1の文字数≦50
P2の文字数≦50
zeroCount≦10^16
方針
P1,P2に1が現れるかどうかで場合わけ。
どちらにも現れない場合、Tは0だけなので、zeroCountが10^16以下ならOK
P1のみに0が現れないとき、
(100万回P1)+(P2)+(100万回P1)+(P2)なので、
現れ方は三通り。
P2にのみ0が現れないとき、
何回目のP2の出現でzeroCountが現れるかを計算して、その位置を求める。
コーナーケースがかなり多いので難しい。
ソースコード
class RepeatedPatterns { public: long long findZeroSegment(string P1, string P2, string zeroCount) { int n=P1.size(), m=P2.size(); ll zero=atoll(zeroCount.c_str()); bool p1=0, p2=0; rep(i,n)if(P1[i]=='1')p1=1; rep(i,m)if(P2[i]=='1')p2=1; if(!p1&&!p2){ if(zero>(ll)1e16)return -1; return 0; } if(!p1){ int z1=0, z2=0; for(int i=0;P2[i]=='0';i++)z1++; for(int i=m-1;P2[i]=='0';i--)z2++; if(zero<=1000000ll*n+z1)return 0; if(zero<=1000000ll*n+z1+z2)return 1000000ll*n+m-z2; return -1; } if(zero<=max(n,m)*2){ string tmp=P1+P1; int p=tmp.find(string(zero,'0')); if(p!=string::npos)return p; tmp=P1+P2+P1; p=tmp.find(string(zero,'0')); if(p!=string::npos)return ll(1000000-1)*n+p; tmp=P2+P1+P2; p=tmp.find(string(zero,'0')); if(p!=string::npos)return 1000000ll*n+p; tmp=P1+P2+P2; p=tmp.find(string(zero,'0')); if(p!=string::npos)return (2000000ll-1)*n+m+p; } if(p2)return -1; int z=0, zpos=n; for(int i=0;P1[i]=='0';i++)z++; for(int i=n-1;P1[i]=='0';i--)z++, zpos--; ll pos=(zero-z+m-1)/m; if((1000000.0*pos-1)*n+pos*(pos-1.0)/2*m+zpos>=1e17)return -1; pos=(1000000*pos-1)*n+pos*(pos-1)/2*m+zpos; if(pos+zero>(ll)1e16)return -1; return pos; } };