意外にハマった。
http://codeforces.com/contest/898/problem/F
問題
N文字数字が並んでいる。
途中"+"と"="を挟み、A+B=Cという式が成り立つような形にせよ。
解法
Cの長さを総当たりする。
A,Bの少なくとも片方はCと同じかCより1少ない桁数でなければならないので、A,Bの候補は高々4通りに定まる。
あとはA+B=Cがなりたつか、またLeading Zeroがないかと判定しよう。
とはいえ、Cの長さをO(N)通り総当たりし、その都度O(N)かけて加算判定をしていては間に合わない。
よって、ローリングハッシュの要領でA,B,C相当部分を数値とみなした場合のハッシュ値を計算しておこう。
そうすると真面目に全桁加算判定しなくても、ハッシュ値の加算でA+B=Cが判定できる。
int N; string S; struct RollingHash { static const ll mo0=1000000007,mo1=1000000009; static const ll mul0=10,mul1=10; static const ll add0=0, add1=0; static vector<ll> pmo[2]; string s; int l; vector<ll> hash_[2]; void init(string s) { this->s=s; l=s.size(); int i,j; hash_[0]=hash_[1]=vector<ll>(1,0); if(pmo[0].empty()) pmo[0].push_back(1),pmo[1].push_back(1); FOR(i,l) hash_[0].push_back((hash_[0].back()*mul0+add0+s[i])%mo0); FOR(i,l) hash_[1].push_back((hash_[1].back()*mul1+add1+s[i])%mo1); } pair<ll,ll> hash(int l,int r) { // s[l..r] if(l>r) return make_pair(0,0); while(pmo[0].size()<r+2) pmo[0].push_back(pmo[0].back()*mul0%mo0), pmo[1].push_back(pmo[1].back()*mul1%mo1); return make_pair((hash_[0][r+1]+(mo0-hash_[0][l]*pmo[0][r+1-l]%mo0))%mo0, (hash_[1][r+1]+(mo1-hash_[1][l]*pmo[1][r+1-l]%mo1))%mo1); } }; vector<ll> RollingHash::pmo[2]; RollingHash rh; void hoge(int a,int b,int c) { auto X=rh.hash(0,a-1); auto Y=rh.hash(a,a+b-1); auto Z=rh.hash(a+b,a+b+c-1); if(a>1 && S[0]=='0') return; if(b>1 && S[a]=='0') return; if(c>1 && S[a+b]=='0') return; if((X.first+Y.first)%1000000007!=Z.first) return; if((X.second+Y.second)%1000000009!=Z.second) return; cout<<S.substr(0,a)<<"+"<<S.substr(a,b)<<"="<<S.substr(a+b)<<endl; exit(0); } void solve() { int i,j,k,l,r,x,y; string s; cin>>S; N=S.size(); FORR(c,S) c-='0'; rh.init(S); FORR(c,S) c+='0'; for(int R=1;R<=N;R++) { for(int A=R-1;A<=R;A++) { int B=N-A-R; if(B<=0 || B>A) continue; hoge(A,B,R); if(A!=B) hoge(B,A,R); } } }
まとめ
何気にローリングハッシュは思いつかず。