Problem:
未知の病原菌
英世博士は未知の病原菌を発見しました。この病原菌は、アクダマキンとゼンダマキンと呼ばれる二種類の菌が、一直線に連なった鎖状の構造をしています。人類のために、この病原菌を無害化したいと考えています。
この病原菌は、長さが２以下になると力が弱まり、免疫力によって無害化されることが分かっています。英世博士は、この病原菌を任意の場所で切断して、前半と後半の２つの鎖にすることができます。また、２つの鎖を連結して１つの鎖にすることもできます。
しかし注意しなければいけないのは、アクダマキンの数が多い鎖はきわめて有害だということです。ある鎖においてアクダマキンの数がゼンダマキンの数よりも多くなると、その瞬間アクダマキンは無制限に増殖を始めます。これは長さ２以下の鎖についても例外ではないので、慎重に鎖を切断していかなければなりません。
どの瞬間においてもアクダマキンの数の方が多いような鎖を作ることなく、一本の鎖を長さ２以下にして無害化することは可能でしょうか。英世博士は、助手であるあなたに無害化が可能かどうか判定するプログラムを作成するよう指示しました。無害化が可能ならばその操作を出力し、不可能ならば不可能であると出力するプログラムを作成してください。ただし、その操作のステップ数が最小である必要はありません。
入力
入力は以下の形式で与えられる。
Q
str
1
str
2
:
str
Q
1 行目に病原菌の数
Q
(1 ≤
Q
≤ 300) が与えられる。続く
Q
行に各病原菌の初期状態を表す '
o
' (ゼンダマキン) および '
x
' (アクダマキン) からなる１つの文字列
str
i
が与えられる。文字列
str
i
の長さは 1 以上 100 以下である。
出力
str
i
について、要求を満たす切断・結合操作の列が存在する場合、出力の最初の行にはその操作列の長さを表す整数
n
を出力し、続く
n
行に操作の内容を１行に１操作ずつ、最初の操作から順に出力する。
切断操作は以下の形式で表すこと。
split
a
p
a
は切断する鎖の識別番号を表す整数であり、
p
はその鎖を切断する位置である。この操作の結果、鎖
a
は先頭から
p
番目（先頭を 0 から始める通し番号)の菌の直後で切断される。新しくできる２つの鎖のうち、前半のものに識別番号
m
+1 が、後半のものに識別番号
m
+2 が付与される（ここで、
m
はこれまでに付与された最も大きな識別番号を表す）。また、鎖
a
は消滅する。
結合操作は以下の形式で表すこと。
join
a
b
a
,
b
は結合する鎖の識別番号を表す整数である。この操作の結果、鎖
a
の末尾に鎖
b
の先頭を結合した新しい鎖が作られる。新しく作られた鎖には、識別番号
m
+1 が付与される(ここで、
m
はこれまでに付与された最も大きな識別番号を表す)。また、鎖
a
,
b
は消滅する。
入力として与えられる最初の鎖には、識別番号 0 が付与されている。
操作の結果、問題の要求を満たすように鎖が分解されていた場合、どのような操作でも正答と判定される。操作列の長さも必ずしも最短である必要はない。ただし、操作列の長さは 20000 以下でなければならない。データセットにおいて、鎖が分解可能な場合、必ずこの条件を満たす操作列が存在することが保証される。
不正な操作列が出力された場合、誤答と判定される。不正な操作列には、以下の場合が含まれる。
切断操作
split
a
p
において、0 ≤
p
< (鎖
a
の長さ)-1 が満たされていない場合。
切断・結合操作の対象となる鎖の識別番号がまだ生成されていないものである場合や、既に別の操作の対象となったため消滅している場合。
結合操作
join
a
b
において、
a
と
b
が等しい場合。
要求を満たす切断・結合操作の列が存在しない場合、"
-1
"と出力する。
入出力例
入力例
6
oooxxxx
ooooxxx
oxxooxxo
ooxx
oo
ooo
出力例
-1
7
split 0 0
join 2 1
split 3 4
split 4 0
join 7 6
split 8 2
split 9 0
3
split 0 1
split 2 1
split 4 1
-1
0
1
split 0 0
例えば、入力例の２番目の病原菌
ooooxxx
は、
split
0 0 により
o
(1) と
oooxxx
(2) ができる。ここで、()内の数字は識別番号を表す。
join
2 1 により
oooxxxo
(3) ができ 1 と 2 は消滅する。
split
3 4 により
oooxx
(4) と
xo
(5) ができる。このとき{
oooxx
(4),
xo
(5) }の鎖が存在する。
split
4 0 により
o
(6) と
ooxx
(7) ができる。{
xo
(5),
o
(6),
ooxx
(7)}
join
7 6 により
ooxxo
(8) ができる。{
xo
(5),
ooxxo
(8)}
split
8 2 により
oox
(9) と
xo
(10) ができる。{
xo
(5),
oox
(9),
xo
(10) }
split
9 0 により {
xo
(5),
xo
(10),
o
(11),
ox
(12) } となって終了する。

Submitted solutions:

code_snippet: // AOJ #313
// Unknown Germ 2025.2.9

#include <bits/stdc++.h>
using namespace std;
 
struct Chain {
    int id;
    string s;
};
 
bool isSafe(const string &s) {
    int countO = 0, countX = 0;
    for(char c : s) {
        if(c=='o') countO++;
        else if(c=='x') countX++;
    }
    return (countO >= countX);
}
 
int findSplitPos(const string &s) {
    int n = s.size();
    int best = -1;
    int bestMax = 1e9;
    for (int p = 0; p < n-1; p++){
        string left = s.substr(0, p+1);
        string right = s.substr(p+1);
        if(isSafe(left) && isSafe(right)){
            if(left.size() <= 2 || right.size() <= 2)
                return p;
            int candidate = max((int)left.size(), (int)right.size());
            if(candidate < bestMax){
                bestMax = candidate;
                best = p;
            }
        }
    }
    return best;
}
 
struct JoinResult {
    bool possible;
    int order;
    string joined;
};
 
JoinResult tryJoinChains(const Chain &A, const Chain &B) {
    JoinResult res;
    res.possible = false;
    for (int order = 1; order >= 0; order--){
        string joined;
        if(order==0) joined = A.s + B.s;
        else joined = B.s + A.s;
        if(!isSafe(joined)) continue;
        if(joined.size() <= 2){
            res.possible = true;
            res.order = order;
            res.joined = joined;
            return res;
        }
        int pos = findSplitPos(joined);
        if(pos != -1){
            res.possible = true;
            res.order = order;
            res.joined = joined;
            return res;
        }
    }
    return res;
}
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
 
    int Q;
    cin >> Q;
    for(int qi=0; qi<Q; qi++){
        string init;
        cin >> init;
 
        if(!isSafe(init)){
            cout << -1 << endl;
            continue;
        }
 
        if(init.size() <= 2){
            cout << 0 << endl;
            continue;
        }
 
        vector<string> operations;
        vector<Chain> chains;
        int maxId = 0;
        chains.push_back({0, init});
 
        int opCount = 0;
        const int opLimit = 20000;
 
        bool progress = true;
        while(progress && opCount < opLimit) {
            bool allFinal = true;
            for(auto &ch : chains){
                if(ch.s.size() > 2){
                    allFinal = false;
                    break;
                }
            }
            if(allFinal) break;
 
            progress = false;
 
            for (int i = 0; i < (int)chains.size(); i++){
                if(chains[i].s.size() > 2){
                    int pos = findSplitPos(chains[i].s);
                    if(pos != -1){
                        int a_id = chains[i].id;
                        string s = chains[i].s;
                        operations.push_back("split " + to_string(a_id) + " " + to_string(pos));
                        opCount++;
                        string leftStr = s.substr(0, pos+1);
                        string rightStr = s.substr(pos+1);
                        int newId1 = maxId + 1;
                        int newId2 = maxId + 2;
                        maxId += 2;
                        Chain leftChain = {newId1, leftStr};
                        Chain rightChain = {newId2, rightStr};
 
                        chains.erase(chains.begin() + i);
                        chains.push_back(leftChain);
                        chains.push_back(rightChain);
 
                        progress = true;
                        break;
                    }
                }
            }
            if(progress) continue;
 
            if(chains.size() >= 2){
                bool joined = false;
                for (int i = 0; i < (int)chains.size() && !joined; i++){
                    for (int j = i+1; j < (int)chains.size() && !joined; j++){
                        if(chains[i].s.size() <= 2 && chains[j].s.size() <= 2) continue;
 
                        JoinResult jr = tryJoinChains(chains[i], chains[j]);
                        if(jr.possible){
                            if(jr.order == 0){
                                operations.push_back("join " + to_string(chains[i].id) + " " + to_string(chains[j].id));
                            } else {
                                operations.push_back("join " + to_string(chains[j].id) + " " + to_string(chains[i].id));
                            }
                            opCount++;
 
                            int newId = maxId + 1;
                            maxId += 1;
                            Chain newChain = {newId, jr.joined};
 
                            if(j > i) {
                                chains.erase(chains.begin() + j);
                                chains.erase(chains.begin() + i);
                            } else {
                                chains.erase(chains.begin() + i);
                                chains.erase(chains.begin() + j);
                            }
                            chains.push_back(newChain);
                            joined = true;
                            progress = true;
                            break;
                        }
                    }
                }
                if(joined) continue;
            }
 
            break;
        }
 
        bool finalState = true;
        for(auto &ch : chains){
            if(ch.s.size() > 2) { finalState = false; break; }
        }
 
        if(!finalState) cout << -1 << endl;
        else {
            cout << operations.size() << endl;
            for(auto &op : operations)
                cout << op << endl;
        }
    }
    return 0;
}
accuracy: 0.25
time_ms: 60
memory_kb: 5004
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define int long long
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;
#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,f,n) for(int i=(f);i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define each(it,v) for(__typeof((v).begin()) it=(v).begin();it!=(v).end();it++)
#define pb push_back
#define fi first
#define se second
template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}


int K;
int itm;
vector<string>ope;
vector<int>idx1,idx2;

inline void add(const string &s,int i,int j){
    ope.pb(s);
    idx1.pb(i);
    idx2.pb(j);
    if(s=="split")K+=2;
    else K++;
}

void dfs(int k,string s){
    int X=count(all(s),'o')-count(all(s),'x');
    assert(X>=0);
    if(X==s.size()){
        if(itm!=-1)return;
        if(X==1)itm=k;
        else{
            add("split",k,0);
            itm=K-1;
        }
        return;
    }
    if(s.size()<=2)return;

    int st=0;
    rep(i,s.size()){
        if(s[i]=='o')st++;else st--;
        if(i&&i+2<s.size()&&0<=st&&st<=X);else continue;

        add("split",k,i);
        int x=K-1,y=K;
        if(st){
            dfs(x,s.substr(0,i+1));
            dfs(y,s.substr(i+1,s.size()-i-1));
        }
        else{
            dfs(y,s.substr(i+1,s.size()-i-1));
            dfs(x,s.substr(0,i+1));
        }
        return;
    }

    if(s[0]=='x'){
        if(itm!=-1){
            add("join",itm,k);
            itm=-1;
            dfs(K,"o"+s);
        }
        else{
            add("split",k,s.size()-2);
            itm=K;
            dfs(K-1,s.substr(0,s.size()-1));
        }
    }
    else{
        if(itm!=-1){
            add("join",k,itm);
            itm=-1;
            dfs(K,s+"o");
        }
        else{
            add("split",k,0);
            itm=K-1;
            dfs(K,s.substr(1,s.size()-1));
        }
    }
}

signed main(){
    int N;
    cin>>N;
    while(N--){
        K=0;itm=-1;
        string S;
        cin>>S;
        int a=count(all(S),'o');
        int b=S.size()-a;
        bool flag=true;
        for(int i=0;i+1<S.size();i+=2)if(S[i]==S[i+1])flag=false;
        if(a>b||(a==b&&flag)){
            dfs(0,S);
            cout<<ope.size()<<endl;
            rep(i,ope.size())cout<<ope[i]<<" "<<idx1[i]<<" "<<idx2[i]<<endl;
        }
        else{
            cout<<-1<<endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 3164
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;

struct data{
  int id;
  string str;
  data(int a,string b){id=a;str=b;}
};
struct edge{ int a,b,c; };

queue<data> A,B,C;
vector< edge > ans;
bool flg;
int cnt;

bool check(string s){
  int ac=0,bc=0;
  for(int i=0;i<(int)s.size();i++){
    if(s[i]=='o')ac++;
    else bc++;
  }
  return (ac>=bc);
}

void func(data d){
  int len=d.str.size();
  if(len==1)A.push(d);
  else B.push(d);
}

void solve(){
  int key=0;
  while(!C.empty()){
    
    if( key++ > 50000){ flg=true; return; }
    
    data d=C.front();C.pop();
    string s=d.str;
    int i;
    if(!check(s)){ flg=true; return; }
    
    if(d.str.size()<=2){ func(d); continue; }

    int O1=0,X1=0,O2=0,X2=0;;
    for(int i=0;i<(int)s.size();i++){
      if(s[i]=='o')O2++;
      else if(s[i]=='x')X2++;
    }
    
    for(i=0;i+1<(int)s.size();i++){
      if(s[i]=='o')O2--,O1++;
      else X2--,X1++;
      
      
      if(O2>=X2&&O1>=X1){
        ans.push_back( (edge){0,d.id,i} );
        string a=s.substr(0,i+1);
        string b=s.substr(i+1);
        data na=data(cnt++,a);
        data nb=data(cnt++,b);        
        C.push(na);
        C.push(nb);
        break;
      }
    }
    if(i+1<(int)s.size())continue;
    if(A.empty()){ C.push(d); continue; }
    data f=A.front();A.pop();
    if( d.str[0]=='x'){
      ans.push_back( (edge){ 1 , f.id , d.id } );
      cnt++;
      ans.push_back( (edge){ 0 , cnt , 1 } );
      B.push( (data){ cnt++, "ox" } );
      C.push( (data){ cnt++, s.substr(2)} );
    }else{
      ans.push_back( (edge){ 1 , d.id , f.id } );
      cnt++;
      ans.push_back( (edge){ 0 , cnt , (int)s.size()-2 } );
      B.push( (data){ cnt++, "xo" } );
      C.push( (data){ cnt++, s.substr(0, (int)s.size()-2 )} );
    }
  }
  if(!C.empty())flg=true;
}

int main(){
  int Tc;
  cin>>Tc;
  while(Tc--){
    cnt=1;
    while(!A.empty())A.pop();
    while(!B.empty())B.pop();
    while(!C.empty())C.pop();
    ans.clear();
    string st;
    cin>>st;
    if(st.size()==1){
      if(st=="o")cout<<0<<endl;
      else cout<<-1<<endl;
      continue;
    }else if(st.size()==2){
      if(st=="xx")cout<<-1<<endl;
      else cout<<0<<endl;
      continue;
    }
    
    C.push( data(0,st) );
    flg=false;
    solve();
    
    if(flg){
      cout<<-1<<endl;
    }else{
      cout<<ans.size()<<endl;
      for(int i=0;i<(int)ans.size();i++){
        edge e=ans[i];
        if(e.a==0)printf("split ");
        else printf("join ");
        printf("%d %d\n",e.b,e.c);
      }
    }
  }
  return 0;
}
accuracy: 1
time_ms: 410
memory_kb: 1280
final_rank: 2