Problem:
Into the Wild
In recent years, the country of Izua has been plagued by animals that come down from the mountains to the city. You have done a lot of research to try to bring the animals back to the mountains, and you have discovered the following.
Each animal has a unique name.
If you insert a letter anywhere in the name of one of the two animals, and it matches the name of the other animal, you can pair them up and send them back to the mountain.
Once an animal has returned to the mountain, it will not come down to the city again.
You have decided to calculate how many animals that have come down to the city can be sent back to the mountain in this way.
Given the names of the animals that have come down to the city, write a program to find the maximum number of pairs that can be sent back up the mountain in this way.
Input
The input is given in the following form.
$N$
$str_1$
$str_2$
:
$str_N$
The first line gives the number of animals $N$ ($2 \leq N \leq 100,000$). In the following $N$ lines, the string $str_i$ representing the name of the $i$-th animal is given. $str_i$ is a string of no more than 10 characters consisting of lowercase and uppercase letters. Also, the names of all animals are different ($str_i \ne str_j$ if $i \ne j$).
Output
Output the maximum number of pairs of animals that can be sent back to the mountain.
Sample Input and Output
Sample Input 1
4
aedb
aeb
ebCd
cdE
Sample Output 1
1
Sample Input 2
4
bcD
bD
AbD
bc
Sample Output 2
2

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(n);++i)
using namespace std;
using ll = long long;

struct Bipartite_Matching
{
  vector< vector< int > > graph;
  vector< int > dist, match;
  vector< bool > used, vv;

  Bipartite_Matching(int n, int m)
  {
    graph.resize(n);
    match.assign(m, -1);
    used.assign(n, false);
  }

  void add_edge(int u, int v)
  {
    graph[u].push_back(v);
  }

  void bfs()
  {
    dist.assign(graph.size(), -1);
    queue< int > que;
    for(int i = 0; i < graph.size(); i++) {
      if(!used[i]) {
        que.emplace(i);
        dist[i] = 0;
      }
    }

    while(!que.empty()) {
      int a = que.front();
      que.pop();
      for(auto &b : graph[a]) {
        int c = match[b];
        if(c >= 0 && dist[c] == -1) {
          dist[c] = dist[a] + 1;
          que.emplace(c);
        }
      }
    }
  }

  bool dfs(int a)
  {
    vv[a] = true;
    for(auto &b : graph[a]) {
      int c = match[b];
      if(c < 0 || (!vv[c] && dist[c] == dist[a] + 1 && dfs(c))) {
        match[b] = a;
        used[a] = true;
        return (true);
      }
    }
    return (false);
  }

  int bipartite_matching()
  {
    int ret = 0;
    while(true) {
      bfs();
      vv.assign(graph.size(), false);
      int flow = 0;
      for(int i = 0; i < graph.size(); i++) {
        if(!used[i] && dfs(i)) ++flow;
      }
      if(flow == 0) return (ret);
      ret += flow;
    }
  }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    
    int n;
    cin >> n;
    vector<string> s(n);
    rep(i,n) cin >> s[i];


    int m = 0;
    rep(i,n){
        if(s[i].size()%2) m++;
    }

    Bipartite_Matching g(n-m,m);

    map<string,int> ma;
    {
        int l=0,r=0;
        rep(i,n) {
            if(s[i].size()%2==0) ma[s[i]]=l++;
            else ma[s[i]]=r++;
        }
    }

    rep(i,n){
        rep(j,s[i].size()){
            string t;
            rep(k,s[i].size()){
                if(j==k) continue;
                t += s[i][k];
            }
            if(ma.count(t)){
                int a=ma[s[i]],b=ma[t];
                if(s[i].size()%2) swap(a,b);
                g.add_edge(a,b);
            }
        }
    }

    int ans = g.bipartite_matching();
    cout << ans << endl;

}
accuracy: 1
time_ms: 400
memory_kb: 21808
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)

template<class T>
using vi = vector<T>;

template<class T>
using vii = vector<vi<T>>;

template<class T>
using viii = vector<vii<T>>;

struct Dinic {
private:
    const long long inf = 1e18;
    vector<int> dist; //sからの距離
    vector<int> iter; //どこまで調べたか
public:
    struct edge {
        int to, rev; long long cap;
        edge(int t = 0, int r = 0, long long c = 0LL) : to(t), rev(r), cap(c) {}
    };

    int n;
    vector<vector<edge>> to;

    Dinic(int n_ = 1) : n(n_), to(n_), dist(n_), iter(n_) {}

    void addedge(int u, int v, long long cap) {//u->vにcapの容量
        int su = (int)to[u].size(), sv = (int)to[v].size();
        to[u].push_back({ v, sv, cap });
        to[v].push_back({ u, su, 0 });
    }

    long long dfs(int v, int t, long long f) { //t: 終点, f: flow
        if (v == t) return f;
        int sv = (int)to[v].size();
        for (int& i = iter[v]; i < sv; i++) {
            edge& nv = to[v][i];
            if (dist[nv.to] <= dist[v] || nv.cap == 0) continue; //here
            long long nf = dfs(nv.to, t, min(f, nv.cap));
            if (nf > 0) {
                nv.cap -= nf;
                to[nv.to][nv.rev].cap += nf;
                return nf;
            }
        }
        return 0;
    }

    void bfs(int s) {
        dist.assign(n, -1);
        queue<int> q;
        q.push(s);
        dist[s] = 0;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (auto nv : to[v]) {
                if (nv.cap > 0 && dist[nv.to] < 0) {
                    dist[nv.to] = dist[v] + 1;
                    q.push(nv.to);
                }
            }
        }
    }

    long long maxflow(int s, int t) {//s:始点, t:終点
        long long res = 0, flow = 0;
        while (true) {
            bfs(s);
            if (dist[t] < 0) break;

            iter.assign(n, 0);
            while (flow = dfs(s, t, inf)) res += flow;
        };
        return res;
    }
};


int main()
{
    int n;
    cin >> n;
    map<string, int> mp;
    rep(i, n) {
        string s;
        cin >> s;
        mp[s];
    }

    int idx = 0;
    for (auto& elem : mp) elem.second = idx++;

    Dinic dn(n + 2);
    int S = n, T = n + 1;

    for (auto &elem : mp) {
        int sz = (int)elem.first.size();
        if (sz & 1) dn.addedge(S, elem.second, 1);
        else dn.addedge(elem.second, T, 1);

        rep(i, sz) {
            string s = elem.first.substr(0, i) + elem.first.substr(i + 1);
            if (mp.count(s)) {
                if (sz & 1) dn.addedge(elem.second, mp[s], 1);
                else dn.addedge(mp[s], elem.second, 1);
            }
        }
    }

    ll flow = dn.maxflow(S, T);
    cout << flow << endl;

    return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 61100
final_rank: 11

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


#include <algorithm>
#include <cassert>
#include <limits>
#include <queue>
#include <vector>


#include <vector>

namespace atcoder {

namespace internal {

template <class T> struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

template <class Cap> struct mf_graph {
  public:
    mf_graph() : _n(0) {}
    explicit mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        int from_id = int(g[from].size());
        int to_id = int(g[to].size());
        if (from == to) to_id++;
        g[from].push_back(_edge{to, to_id, cap});
        g[to].push_back(_edge{from, from_id, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) return res;
            }
            level[v] = _n;
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            Cap f = dfs(dfs, t, flow_limit - flow);
            if (!f) break;
            flow += f;
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

  private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

using namespace atcoder;

int main() {
  int N;
  cin >> N;
  unordered_map<string, int> mp;
  for( int i = 0; i < N; i++ ) {
    string str;
    cin >> str;
    mp[str] = i;
  }
  mf_graph<int> G(N+2);
  for( const auto &[s, i] : mp ) {
    if( s.size()%2 == 0 ) {
      G.add_edge(N, i, 1);
    }else {
      G.add_edge(i, N+1, 1);
    }
    for( int j = 0; j < int(s.size()); j++ ) {
      string t(s.begin(), s.end());
      t.erase(t.begin()+j);
      if( mp.count(t) ) {
        if( s.size()%2 == 0 ) {
          G.add_edge(i, mp[t], 1);
        }else {
          G.add_edge(mp[t], i, 1);
        }
      }
    }
  }
  cout << G.flow(N, N+1) << endl;
}
accuracy: 1
time_ms: 210
memory_kb: 59756
final_rank: 8

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


#include <algorithm>
#include <cassert>
#include <limits>
#include <queue>
#include <vector>


#include <vector>

namespace atcoder {

namespace internal {

template <class T> struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

template <class Cap> struct mf_graph {
  public:
    mf_graph() : _n(0) {}
    explicit mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        int from_id = int(g[from].size());
        int to_id = int(g[to].size());
        if (from == to) to_id++;
        g[from].push_back(_edge{to, to_id, cap});
        g[to].push_back(_edge{from, from_id, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) return res;
            }
            level[v] = _n;
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            Cap f = dfs(dfs, t, flow_limit - flow);
            if (!f) break;
            flow += f;
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

  private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

using namespace atcoder;

int main() {
  int N;
  cin >> N;
  unordered_map<string, int> mp;
  for( int i = 0; i < N; i++ ) {
    string str;
    cin >> str;
    mp[str] = i;
  }
  mf_graph<int> G(N+2);
  for( const auto &[str, i] : mp ) {
    if( str.size()%2 == 0 ) {
      G.add_edge(i, N+1, 1);
    }else {
      G.add_edge(N, i, 1);
      for( int j = 0; j < int(str.size()); j++ ) {
        string str_op(str.begin(), str.end());
        str_op.erase(str_op.begin()+j);
        if( mp.count(str_op) ) G.add_edge(i, mp[str_op], 1);
      }
      for( int j = 0; j <= int(str.size()); j++ ) {
        string str_op(str.begin(), str.end());
        str_op.insert(str_op.begin()+j, '*');
        for( char c = 'a'; c <= 'z'; c++ ) {
          str_op[j] = c;
          if( mp.count(str_op) ) G.add_edge(i, mp[str_op], 1);
        }
        for( char c = 'A'; c <= 'Z'; c++ ) {
          str_op[j] = c;
          if( mp.count(str_op) ) G.add_edge(i, mp[str_op], 1);
        }
      }
    }
  }
  cout << G.flow(N, N+1) << endl;
}
accuracy: 1
time_ms: 2970
memory_kb: 57092
final_rank: 16

code_snippet: #include <bits/stdc++.h>

struct Edge {
    Edge(int f, int t, int c, int fl, int r): from(f), to(t), cap(c), flow(fl), rev(r) {}
    int from;
    int to;
    int cap;
    int flow;
    int rev;
};

int flow(std::vector<std::vector<Edge>> graph, const int source, const int sink) {
    int n = graph.size();
    std::vector<bool> used(n);
    auto dfs = [&](auto self, int u) -> bool {
        if (u == sink) return true;
        used[u] = true;
        for (auto& e: graph[u]) {
            if (used[e.to]) continue;
            if (e.flow == 1) continue;
            if (self(self, e.to)) {
                e.flow = 1;
                graph[e.to][e.rev].flow = 0;
                return true;
            }
        }
        return false;
    };
    int ans = 0;
    while (true) {
        if (dfs(dfs, source)) {
            ans++;
            while (dfs(dfs, source)) ans++;
        } else {
            break;
        }
        used.assign(n, false);
    }
    return ans;
}

int main() {
    int n;
    std::cin >> n;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; i++) std::cin >> s[i];
    constexpr int LEN = 11;
    std::array<std::vector<int>, LEN> str;
    std::map<std::string, int> mapping;
    for (int i = 0; i < n; i++) {
        str[s[i].size()].push_back(i);
        mapping[s[i]] = i;
    }
    const int source = n;
    const int sink = n + 1;
    std::vector graph(n + 2, std::vector<Edge>());
    auto add_edge = [&](int from, int to) {
        int i = graph[from].size();
        int j = graph[to].size();
        graph[from].emplace_back(from, to, 1, 0, j);
        graph[to].emplace_back(to, from, 1, 1, i);
    };
    for (int i = 1; i < LEN; i++) {
        for (int j: str[i]) {
            if (i % 2 == 1) {
                add_edge(source, j);
            } else {
                add_edge(j, sink);
            }
        }
    }
    for (int i = 1; i < LEN; i++) {
        for (int j: str[i]) {
            std::string t = s[j];
            for (int k = 0; k < (int)t.size(); k++) {
                std::string u = t;
                u.erase(u.begin() + k);
                if (mapping.find(u) != mapping.end()) {
                    int l = mapping[u];
                    if (i % 2 == 1) {
                        add_edge(j, l);
                    } else {
                        add_edge(l, j);
                    }
                }
            }
        }
    }
    std::cout << flow(graph, source, sink) << '\n';
}
accuracy: 1
time_ms: 1730
memory_kb: 113536
final_rank: 17

code_snippet: #include<bits/stdc++.h>
#define overload(a,b,c,d,...) d
#define rep1(a) for(ll _=0;_<(ll)a;++_)
#define rep2(i,n) for(ll i=0;i<(ll)n;++i)
#define rep3(i,l,r) for(ll i=(ll)l;i<(ll)r;++i)
#define rep(...) overload(__VA_ARGS__,rep3,rep2,rep1)(__VA_ARGS__)
#define rrep1(i,a) for(ll i=(ll)a-1;i>=0;--i)
#define rrep2(i,a,b) for(ll i=(ll)b-1;i>=(ll)a;--i)
#define rrep(...) overload(__VA_ARGS__,rrep2,rrep1)(__VA_ARGS__)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define eb emplace_back
using namespace std;
using ll=long long;
using ull=unsigned long long;
using ld=long double;
template<typename T,typename U>inline bool chmin(T&a,const U&b){return (a>b?a=b,true:false);}
template<typename T,typename U>inline bool chmax(T&a,const U&b){return (a<b?a=b,true:false);}
static constexpr ll mod1=998244353;
static constexpr ll mod=1000000007;
struct Dinic{
	struct Edge{
		int to;
		int cap;
		int rev;
		int isrev;
		int idx;
	};
	vector<vector<Edge>>g;
	vector<int>min_cost,iter;
	const int INF=numeric_limits<int>::max()/2;
	Dinic(int v):g(v){}
	void add_edge(int from,int to,int cap,int idx=-1){
		g[from].eb(Edge{to,cap,(int)g[to].size(),false,idx});
		g[to].eb(Edge{from,0,(int)g[from].size()-1,true,idx});
	}
	bool build_path(int s,int t){
		min_cost.assign(g.size(),-1);
		queue<int>q;
		min_cost[s]=0;
		q.push(s);
		while(!q.empty()&&min_cost[t]==-1){
			int v=q.front();q.pop();
			for(auto&e:g[v]){
				if(e.cap>0&&min_cost[e.to]==-1){
					min_cost[e.to]=min_cost[v]+1;
					q.push(e.to);
				}
			}
		}
		return min_cost[t]!=-1;
	}
	int find_path(int idx,const int t,int flow){
		if(idx==t)return flow;
		for(int &i=iter[idx];i<(int)g[idx].size();++i){
			Edge&e=g[idx][i];
			if(e.cap>0&&min_cost[e.to]>min_cost[idx]){
				int d=find_path(e.to,t,min(flow,e.cap));
				if(d>0){
					e.cap-=d;
					g[e.to][e.rev].cap+=d;
					return d;
				}
			}
		}
		return 0;
	}
	int max_flow(int s,int t){
		int flow=0;
		while(build_path(s,t)){
			iter.assign(g.size(),0);
			int f;
			while((f=find_path(s,t,INF))>0)flow+=f;
		}
		return flow;
	}
};
int main(){
	int n;cin>>n;
	vector<string>s(n);
	for(auto&e:s)cin>>e;
	map<string,int>st;
	rep(i,s.size())st[s[i]]=i;
	Dinic d(n+2);
	rep(i,n){
		set<int>to;
		rep(j,s[i].size()){
			string t=s[i].substr(0,j)+s[i].substr(j+1);
			if(st.count(t))to.insert(st[t]);
		}
		for(auto k:to){
			if(s[i].size()%2==0)d.add_edge(i,k,1);
			else d.add_edge(k,i,1);
		}
		if(s[i].size()%2==0)d.add_edge(n,i,1);
		else d.add_edge(i,n+1,1);
	}
	cout<<d.max_flow(n,n+1)<<endl;
}
accuracy: 1
time_ms: 420
memory_kb: 51504
final_rank: 6

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 0424.cc:  Into the Wild
 */

#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int MAX_L = 10;

/* typedef */

typedef vector<int> vi;
typedef vector<string> vst;
typedef vector<bool> vb;

/* global variables */

vst svs[MAX_L + 1];
vi nbrs[MAX_N];

/* subroutines */

bool max_match_rec(const vi *nbrs, int u, vi &matches, vb &visited) {
  if (u < 0) return true;
  for (const int v: nbrs[u]) {
    if (! visited[v]) {
      visited[v] = true;
      if (max_match_rec(nbrs, matches[v], matches, visited)) {
	matches[u] = v;
	matches[v] = u;
	return true;
      }
    }
  }
  return false;
}

int max_match(const int n, int l, const vi *nbrs, vi &matches) {
  matches.assign(n, -1);
  int count = 0;
  
  for (int u = 0; u < l; u++) {
    vb visited(n, false);
    if (max_match_rec(nbrs, u, matches, visited)) count++;
  }

  return count;
}

/* main */

int main() {
  int n;
  scanf("%d", &n);

  for (int i = 0; i < n; i++) {
    char s[MAX_L + 4];
    scanf("%s", s);
    string t(s);
    svs[t.size()].push_back(t);
  }

  int sum = 0;

  for (int l = MAX_L - 1; l >= 1; l--) {
    vst &sv0 = svs[l], &sv1 = svs[l + 1];
    if (sv0.empty() || sv1.empty()) continue;

    sort(sv0.begin(), sv0.end());
    int m0 = sv0.size(), m1 = sv1.size(), m = m0 + m1;
    for (int i = 0; i < m; i++) nbrs[i].clear();

    for (int i = 0; i < m1; i++) {
      string &s1 = sv1[i];
      int l1 = s1.size();
      for (int j = 0; j < l1; j++) {
	string t = s1.substr(0, j) + s1.substr(j + 1);
	vst::iterator vit = lower_bound(sv0.begin(), sv0.end(), t);
	if (vit != sv0.end() && *vit == t) {
	  int i0 = vit - sv0.begin();
	  nbrs[m0 + i].push_back(i0);
	  nbrs[i0].push_back(m0 + i);
	  //printf("%s->%s\n", s1.c_str(), vit->c_str());
	}
      }
    }

    vi matches;
    sum += max_match(m, m0, nbrs, matches);

    vst tmp;
    for (int i = 0; i < m0; i++)
      if (matches[i] < 0) tmp.push_back(sv0[i]);
    swap(tmp, sv0);
  }  

  printf("%d\n", sum);
  return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 17004
final_rank: 18

code_snippet: #ifdef LOGX
#define _GLIBCXX_DEBUG
#endif
#include<bits/stdc++.h>
using namespace std;

using ll=long long;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep2(i,s,n) for(int i=int(s);i<int(n);i++)
#define all(a) (a).begin(),(a).end()
#define rall(a) (a).rbegin(),(a).rend()
const int big=1e9+7;
//const int big=998244353;
const char newl='\n';
const int inf=1e9+10;
const ll INF=ll(1e18)+10;
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};

struct mf_graph{
    int n;
    struct edge2{
        int to,rev;
        int cap;
    };
    struct edge{
        int from;
        int to;
        int cap,flow;
    };
    vector<pair<int,int>> pos;
    vector<vector<edge2>> g;

    mf_graph(int n):n(n),g(n){}

    void add_edge(int from,int to,int cap){
        pos.push_back({from,{int(g[from].size())}});
        int f_id=int(g[from].size());
        int to_id=int(g[to].size());
        if(from==to)to_id++;
        g[from].push_back(edge2{to,to_id,cap});
        g[to].push_back(edge2{from,f_id,0});
        return;
    }

    int flow(int s,int t,int flow_lim=inf){
        vector<int> lev(n),iter(n);
        queue<int> q;
        auto bfs=[&](){
            fill(all(lev),-1);
            lev[s]=0;
            q=queue<int>();
            q.push(s);
            while(!q.empty()){
                int v=q.front();
                q.pop();
                for(auto e:g[v]){
                    if(e.cap==0 || lev[e.to]>=0)continue;
                    lev[e.to]=lev[v]+1;
                    if(e.to==t)return;
                    q.push(e.to);
                }
            }
        };
        auto dfs=[&](auto self,int v,int up){
            if(v==s)return up;
            int res=0;
            int lev_v=lev[v];
            for(int &i=iter[v];i<int(g[v].size());i++){
                edge2& e=g[v][i];
                if(lev_v<=lev[e.to] || g[e.to][e.rev].cap==0)continue;
                int d=self(self,e.to,min(up-res,g[e.to][e.rev].cap));
                if(d<=0)continue;
                g[v][i].cap+=d;
                g[e.to][e.rev].cap-=d;
                res+=d;
                if(res==up)return res;
            }
            lev[v]=n;
            return res;
        };

        int flow=0;
        while(flow<flow_lim){
            bfs();
            if(lev[t]==-1)break;
            fill(all(iter),0);
            int f=dfs(dfs,t,flow_lim-flow);
            if(!f)break;
            flow+=f;
        }
        return flow;
    }
};


int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(10);

    int n;
    cin >> n;
    unordered_map<string,int> ma;
    rep(i,n){
        string s;
        cin >> s;
        ma[s]=i;
    }
    mf_graph g(n+2);
    for(auto it:ma){
        const string s=it.first;
        if(s.size()==1)continue;
        const int i=it.second;
        rep(sz,s.size()){
            string t=s.substr(0,sz)+s.substr(sz+1);
            if(ma.count(t)){
                int from=i,to=ma[t];
                if(s.size()%2)swap(from,to);
                g.add_edge(from,to,1);
            }
        }
    }
    for(auto it:ma){
        if(it.first.size()%2==0){
            g.add_edge(n,it.second,1);
        }
        else{
            g.add_edge(it.second,n+1,1);
        }
    }
    cout << g.flow(n,n+1) << newl;
}
accuracy: 1
time_ms: 200
memory_kb: 59492
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n)  for(long long i=0;i<(long long)(n);i++)
#define REP(i,k,n) for(long long i=k;i<(long long)(n);i++)
#define pb emplace_back
#define lb(v,k) (lower_bound(all(v),(k))-v.begin())
#define ub(v,k) (upper_bound(all(v),(k))-v.begin())
#define fi first
#define se second
#define pi M_PI
#define PQ(T) priority_queue<T>
#define SPQ(T) priority_queue<T,vector<T>,greater<T>>
#define dame(a) {out(a);return 0;}
#define decimal cout<<fixed<<setprecision(15);
#define all(a) a.begin(),a.end()
#define rsort(a) {sort(all(a));reverse(all(a));}
#define dupli(a) {sort(all(a));a.erase(unique(all(a)),a.end());}
#define popcnt __builtin_popcountll
typedef long long ll;
typedef pair<ll,ll> P;
typedef tuple<ll,ll,ll> PP;
typedef tuple<ll,ll,ll,ll> PPP;
using vi=vector<ll>;
using vvi=vector<vi>;
using vvvi=vector<vvi>;
using vvvvi=vector<vvvi>;
using vp=vector<P>;
using vvp=vector<vp>;
using vb=vector<bool>;
using vvb=vector<vb>;
const ll inf=1001001001001001001;
const ll INF=1001001001;
const ll mod=1000000007;
const double eps=1e-10;
template<class T> bool chmin(T&a,T b){if(a>b){a=b;return true;}return false;}
template<class T> bool chmax(T&a,T b){if(a<b){a=b;return true;}return false;}
template<class T> void out(T a){cout<<a<<'\n';}
template<class T> void outp(T a){cout<<'('<<a.fi<<','<<a.se<<')'<<'\n';}
template<class T> void outvp(T v){rep(i,v.size())cout<<'('<<v[i].fi<<','<<v[i].se<<')';cout<<'\n';}
template<class T> void outvvp(T v){rep(i,v.size())outvp(v[i]);}
template<class T> void outv(T v){rep(i,v.size()){if(i)cout<<' ';cout<<v[i];}cout<<'\n';}
template<class T> void outvv(T v){rep(i,v.size())outv(v[i]);}
template<class T> bool isin(T x,T l,T r){return (l)<=(x)&&(x)<=(r);}
template<class T> void yesno(T b){if(b)out("yes");else out("no");}
template<class T> void YesNo(T b){if(b)out("Yes");else out("No");}
template<class T> void YESNO(T b){if(b)out("YES");else out("NO");}
template<class T> void outset(T s){auto itr=s.begin();while(itr!=s.end()){if(itr!=s.begin())cout<<' ';cout<<*itr;itr++;}cout<<'\n';}
void outs(ll a,ll b){if(a>=inf-100)out(b);else out(a);}
ll gcd(ll a,ll b){if(b==0)return a;return gcd(b,a%b);}
ll modpow(ll a,ll b){ll res=1;a%=mod;while(b){if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}

class BipartiteMatching {
	int N, M;
	vector<vector<int>> G;
	vector<bool> used;
	vector<int> p, q;
	bool dfs(int v) {
		if (used[v]) return false;
		used[v] = true;
		for (auto u : G[v]) {
			if (q[u] == -1 || dfs(q[u])) {
				q[u] = v;
				p[v] = u;
				return true;
			}
		}
		return false;
	}

public:
	BipartiteMatching(int n, int m, const vector<vector<int>>& g) : N(n), M(m), G(g), used(N), p(N, -1), q(M, -1) {}
	BipartiteMatching(int n, int m) : N(n), M(m), G(n), used(N), p(N, -1), q(M, -1) {}
	void add_edge(int s, int t) {
		G[s].push_back(t);
	}
	int solve() {
		int res = 0;
		bool flag = true;
		fill(p.begin(), p.end(), -1);
		fill(q.begin(), q.end(), -1);
		fill(used.begin(), used.end(), false);
		while (flag) {
			flag = false;
			for (int i = 0; i < N; ++i) {
				if (p[i] == -1 && dfs(i)) {
					flag = true;
					++res;
				}
			}
			if (flag) {
				fill(used.begin(), used.end(), false);
			}
		}
		return res;
	}
	vector<pair<int, int>> edges() const {
		vector<pair<int, int>> res;
		for (size_t i = 0; i < N; ++i) {
			if (p[i] != -1) {
				res.emplace_back(i, p[i]);
			}
		}
		return res;
	}
};
int main(){
    ll n;cin>>n;
    vector<vector<string>> v(2);
    rep(i,n){
        string s;cin>>s;
        v[s.size()%2].pb(s);
    }
    rep(i,2)sort(all(v[i]));
    BipartiteMatching G(v[0].size(),v[1].size());
    rep(i,2){
        rep(t,v[i].size()){
            string x=v[i][t];
            rep(j,x.size()){
                string tmp;rep(k,x.size())if(j!=k)tmp+=x[k];
                ll l=lb(v[1-i],tmp);
                if(l!=v[1-i].size()&&v[1-i][l]==tmp){
                    if(i)G.add_edge(l,t);
                    else G.add_edge(t,l);
                }
            }
        }
    }
    out(G.solve());
}
accuracy: 1
time_ms: 140
memory_kb: 16184
final_rank: 1

code_snippet: #include <bits/stdc++.h>

using ll = long long;

template <class T> using Vec = std::vector<T>;

struct Edge {
    int to, cap, rev;
};

template <class F> struct RecLambda : private F {
    explicit RecLambda(F&& f) : F(std::forward<F>(f)) {}
    template <class... Args> decltype(auto) operator()(Args&&... args) const {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};


template <class Cap> class Dinic {
    struct Edge {
        int dst, rev;
        Cap cap;
    };

    std::vector<std::vector<Edge>> graph;

  public:
    Dinic() : graph() {}
    explicit Dinic(const int n) : graph(n) {}

    int size() const { return graph.size(); }

    void add_edge(const int src, const int dst, const Cap capacity) {
        assert(0 <= src and src < size());
        assert(0 <= src and dst < size());
        assert(capacity >= 0);
        int src_id = graph[src].size();
        int dst_id = graph[dst].size();
        if (dst == src) dst_id += 1;
        graph[src].push_back(Edge{dst, dst_id, capacity});
        graph[dst].push_back(Edge{src, src_id, 0});
    }

    Cap flow(const int src, const int dst) { return flow(src, dst, std::numeric_limits<Cap>::max()); }
    Cap flow(const int src, const int dst, const Cap flow_limit) {
        assert(0 <= src and src < size());
        assert(0 <= src and dst < size());
        assert(src != dst);
        std::vector<int> level(size()), iter(size());
        std::queue<int> que;
        const auto bfs = [&] {
            std::fill(level.begin(), level.end(), -1);
            level[src] = 0;
            while (!que.empty()) que.pop();
            que.push(src);
            while (!que.empty()) {
                const int u = que.front();
                que.pop();
                for (const Edge& e : graph[u]) {
                    if (e.cap == 0 or level[e.dst] != -1) continue;
                    level[e.dst] = level[u] + 1;
                    if (e.dst == dst) return;
                    que.push(e.dst);
                }
            }
        };
        const auto dfs = [&](auto&& dfs, const int u, const Cap ub) -> Cap {
            if (u == src) return ub;
            Cap ret = 0;
            for (int& i = iter[u]; i < (int)graph[u].size(); i += 1) {
                Edge& e = graph[u][i];
                Edge& re = graph[e.dst][e.rev];
                if (level[u] <= level[e.dst] or re.cap == 0) continue;
                const Cap d = dfs(dfs, e.dst, std::min(ub - ret, re.cap));
                if (d == 0) continue;
                e.cap += d;
                re.cap -= d;
                ret += d;
                if (ret == ub) return ret;
            }
            level[u] = -1;
            return ret;
        };
        Cap ret = 0;
        while (ret < flow_limit) {
            bfs();
            if (level[dst] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            const Cap f = dfs(dfs, dst, flow_limit - ret);
            if (f == 0) break;
            ret += f;
        }
        return ret;
    }
};

int main() {
    int n;
    std::cin >> n;
    Vec<std::string> s(n);
    for (auto& x : s) std::cin >> x;
    std::sort(s.begin(), s.end());
    Dinic<int> graph(n + 2);
    const int src = n;
    const int dst = n + 1;
    for (int i = 0; i < n; ++i) {
        std::set<int> to;
        for (int j = 0; j < (int)s[i].size(); ++j) {
            const std::string x = s[i].substr(0, j) + s[i].substr(j + 1);
            const int k = std::lower_bound(s.begin(), s.end(), x) - s.begin();
            if (k < n and s[k] == x) to.insert(k);
        }
        for (const int k : to) {
            if (s[i].size() % 2 == 0) graph.add_edge(i, k, 1);
            else graph.add_edge(k, i, 1);
        }
        if (s[i].size() % 2 == 0) graph.add_edge(src, i, 1);
        else graph.add_edge(i, dst, 1);
    }
    std::cout << graph.flow(src, dst) << '\n';
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 30648
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using ll = long long;

template <class T> using Vec = std::vector<T>;

int main() {
    int n;
    std::cin >> n;
    Vec<std::string> s(n);
    for (auto& x : s) std::cin >> x;
    std::sort(s.begin(), s.end());
    Vec<Vec<int>> to(n);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < (int)s[i].size(); ++j) {
            const std::string x = s[i].substr(0, j) + s[i].substr(j + 1);
            const int k = std::lower_bound(s.begin(), s.end(), x) - s.begin();
            if (k < n and s[k] == x) {
                to[i].push_back(k);
            }
        }
    }
    Vec<int> idx(n);
    std::iota(idx.begin(), idx.end(), 0);
    std::sort(idx.begin(), idx.end(), [&](const int i, const int j) { return s[i].size() > s[j].size(); });
    Vec<char> used(n);
    int ans = 0;
    for (const int i : idx) {
        for (const int j : to[i]) {
            if (!used[i] and !used[j]) {
                used[i] = used[j] = true;
                ans += 1;
                break;
            }
        }
    }
    std::cout << ans << '\n';
    return 0;
}
accuracy: 0.39285714285714285
time_ms: 130
memory_kb: 8996
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int INF = 1;
template <typename Cap>
struct dinic{
  struct edge{
    int to, rev;
    Cap cap;
    edge(int to, int rev, Cap cap): to(to), rev(rev), cap(cap){
    }
  };
  int N;
  vector<vector<edge>> G;
  dinic(int N): N(N), G(N){
  }
  void add_edge(int from, int to, Cap cap){
    G[from].push_back(edge(to, G[to].size(), cap));
    G[to].push_back(edge(from, G[from].size() - 1, 0));
  }
  Cap dfs(vector<int> &d, vector<int> &iter, int v, int t, Cap f){
    if (v == t){
      return f;
    }
    while (iter[v] < G[v].size()){
      int w = G[v][iter[v]].to;
      if (G[v][iter[v]].cap > 0 && d[v] < d[w]){
        Cap f2 = dfs(d, iter, w, t, min(f, G[v][iter[v]].cap));
        if (f2 > 0){
          G[v][iter[v]].cap -= f2;
          G[w][G[v][iter[v]].rev].cap += f2;
          return f2;
        }
      }
      iter[v]++;
    }
    return 0;
  }
  Cap max_flow(int s, int t){
    Cap flow = 0;
    while (true){
      vector<int> d(N, -1);
      d[s] = 0;
      queue<int> Q;
      Q.push(s);
      while (!Q.empty()){
        if (d[t] != -1){
          break;
        }
        int v = Q.front();
        Q.pop();
        for (auto &e : G[v]){
          int w = e.to;
          if (e.cap > 0 && d[w] == -1){
            d[w] = d[v] + 1;
            Q.push(w);
          }
        }
      }
      if (d[t] == -1){
        break;
      }
      vector<int> iter(N, 0);
      while (true){
        Cap f = dfs(d, iter, s, t, INF);
        if (f == 0){
          break;
        }
        flow += f;
      }
    }
    return flow;
  }
};
int main(){
  int N;
  cin >> N;
  vector<string> str(N);
  for (int i = 0; i < N; i++){
    cin >> str[i];
  }
  map<string, int> mp;
  for (int i = 0; i < N; i++){
    mp[str[i]] = i;
  }
  dinic<int> G(N + 2);
  for (int i = 0; i < N; i++){
    int L = str[i].size();
    if (L % 2 == 0){
      G.add_edge(N, i, 1);
    } else {
      G.add_edge(i, N + 1, 1);
    }
    for (int j = 0; j < L; j++){
      string s = str[i];
      s.erase(s.begin() + j);
      if (mp.count(s) == 1){
        int x = mp[s];
        if (L % 2 == 0){
          G.add_edge(i, x, 1);
        } else {
          G.add_edge(x, i, 1);
        }
      }
    }
  }
  cout << G.max_flow(N, N + 1) << endl;
}
accuracy: 1
time_ms: 410
memory_kb: 54068
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T>>;
template<class T> using vvvc = vc<vvc<T>>;
template<class T> using vvvvc = vvc<vvc<T>>;
template<class T> using PQ = priority_queue<T>;
template<class T> using invPQ = priority_queue<T, vector<T>, greater<T>>;
using IP = pair<int, int>;
using LP = pair<ll, ll>;
#define all(x) begin(x), end(x)
#define allr(x) rbegin(x), rend(x)
#define rep(i, n) for (int i = 0; (i) < (int)(n); i++)
#define rep3(i, m, n) for (int i = (m); (i) < (int)(n); i++)
#define repr(i, n) for (int i = (n) - 1; (i) >= 0; i--)
#define rep3r(i, m, n) for (int i = (n) - 1; (i) >= (int)(m); i--)
template<class T> inline bool chmax(T & a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T & a, T b) { if (a > b) { a = b; return 1; } return 0; }

struct Graph {
    struct Edge {
        int rev, from, to, cap;
        Edge(int r, int f, int t, int c) : rev(r), from(f), to(t), cap(c) {}
    };
    vvc<Edge> list;
    Graph(int N) : list(N) {}
    size_t size() {
        return list.size();
    }
    vc<Edge>& operator [] (int i) {
        return list[i];
    }
    Edge& redge(const Edge& e) {
        return list[e.to][e.rev];
    }
    void run_flow(Edge& e, int f) {
        e.cap -= f;
        redge(e).cap += f;
    }
    void addedge(int from, int to, int cap) {
        int fromrev = (int)list[from].size();
        int torev = (int)list[to].size();
        list[from].push_back(Edge(torev, from, to, cap));
        list[to].push_back(Edge(fromrev, to, from, 0));
    }
};
struct dinic {
    static const int INF = 1 << 30;
    vc<int> seen, level;
    dinic() {}
    void dibfs(Graph& G, int s) {
        level.assign((int)G.size(), -1);
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while (!que.empty()) {
            int v = que.front(); que.pop();
            for (auto& e : G[v]) {
                if (e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    que.push(e.to);
                }
            }
        }
    }
    int didfs(Graph& G, int v, int t, int f) {
        if (v == t) return f;
        seen[v] = true;
        for (auto& e : G[v]) {
            if (seen[e.to]) continue;
            if (e.cap > 0 && level[v] < level[e.to]) {
            int flow = didfs(G, e.to, t, min(f, e.cap));
                if (flow == 0) continue;
                G.run_flow(e, flow);
                return flow;
            }
        }
        return 0;
    }
    int solve(Graph& G, int s, int t) {
        int res = 0;
        while (true) {
            dibfs(G, s);
            if (level[t] < 0) return res;
            seen.assign((int)G.size(), false);
            int flow;
            while ((flow = didfs(G, s, t, INF)) > 0) {
                res += flow;
            }
        }
        return 0;
    }
};

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N;
    cin >> N;
    vc<string> str(N);
    rep (i, N) cin >> str[i];

    sort(all(str), [](string &s1, string &s2) {
        return s1.size() < s2.size();
    });

    Graph G(N+2);
    unordered_map<string, int> mp;
    rep (i, N) {
        rep (j, str[i].size()) {
            if (mp.count(str[i].substr(0, j) + str[i].substr(j+1))) {
                int t = mp[str[i].substr(0, j) + str[i].substr(j+1)];
                if (str[i].size() % 2 == 0) G.addedge(i, t, 1);
                else G.addedge(t, i, 1);
            }
        }
        mp[str[i]] = i;
    }

    rep (i, N) {
        if (str[i].size() % 2 == 0) G.addedge(N, i, 1);
        else G.addedge(i, N+1, 1);
    }

    cout << dinic().solve(G, N, N+1) << endl;
}
accuracy: 1
time_ms: 1120
memory_kb: 62824
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T>>;
template<class T> using vvvc = vc<vvc<T>>;
template<class T> using vvvvc = vvc<vvc<T>>;
template<class T> using PQ = priority_queue<T>;
template<class T> using invPQ = priority_queue<T, vector<T>, greater<T>>;
using IP = pair<int, int>;
using LP = pair<ll, ll>;
#define all(x) begin(x), end(x)
#define allr(x) rbegin(x), rend(x)
#define rep(i, n) for (int i = 0; (i) < (int)(n); i++)
#define rep3(i, m, n) for (int i = (m); (i) < (int)(n); i++)
#define repr(i, n) for (int i = (n) - 1; (i) >= 0; i--)
#define rep3r(i, m, n) for (int i = (n) - 1; (i) >= (int)(m); i--)
template<class T> inline bool chmax(T & a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T & a, T b) { if (a > b) { a = b; return 1; } return 0; }

struct Graph {
    struct Edge {
        int rev, from, to, cap;
        Edge(int r, int f, int t, int c) : rev(r), from(f), to(t), cap(c) {}
    };
    vvc<Edge> list;
    Graph(int N) : list(N) {}
    size_t size() {
        return list.size();
    }
    vc<Edge>& operator [] (int i) {
        return list[i];
    }
    Edge& redge(const Edge& e) {
        return list[e.to][e.rev];
    }
    void run_flow(Edge& e, int f) {
        e.cap -= f;
        redge(e).cap += f;
    }
    void addedge(int from, int to, int cap) {
        int fromrev = (int)list[from].size();
        int torev = (int)list[to].size();
        list[from].push_back(Edge(torev, from, to, cap));
        list[to].push_back(Edge(fromrev, to, from, 0));
    }
};
struct FordFulkerson {
    static const int INF = 1 << 30;
    vc<int> seen;
    FordFulkerson() {}
    int fodfs(Graph& G, int v, int t, int f) {
        if (v == t) return f;
        seen[v] = true;
        for (auto& e : G[v]) {
            if (seen[e.to]) continue;
            if (e.cap == 0) continue;
            int flow = fodfs(G, e.to, t, min(f, e.cap));
            if (flow == 0) continue;
            G.run_flow(e, flow);
            return flow;
        }
        return 0;
    }
    int solve(Graph& G, int s, int t) {
        int res = 0;
        while (true) {
            seen.assign((int)G.size(), 0);
            int flow = fodfs(G, s, t, INF);
            if (flow == 0) return res;
            res += flow;
        }
        return 0;
    }
};

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N;
    cin >> N;
    vc<string> str(N);
    rep (i, N) cin >> str[i];

    sort(all(str), [](string &s1, string &s2) {
        return s1.size() < s2.size();
    });

    Graph G(N+2);
    unordered_map<string, int> mp;
    rep (i, N) {
        rep (j, str[i].size()) {
            if (mp.count(str[i].substr(0, j) + str[i].substr(j+1))) {
                int t = mp[str[i].substr(0, j) + str[i].substr(j+1)];
                G.addedge(i, t, 1);
                G.addedge(t, i, 1);
            }
        }
        mp[str[i]] = i;
    }

    rep (i, N) {
        if (str[i].size() % 2 == 0) G.addedge(N, i, 1);
        else G.addedge(i, N+1, 1);
    }

    cout << FordFulkerson().solve(G, N, N+1) << endl;
}
accuracy: 0.39285714285714285
time_ms: 70
memory_kb: 20600
final_rank: 20

code_snippet: #line 1 "a.cpp"
#include<iostream>
#include<map>
using namespace std;
#line 1 "/home/kotatsugame/library/graph/bimatch.cpp"
#include<algorithm>
#include<vector>
struct bimatch{
	int n;
	vector<vector<int> >G;
	vector<int>match;
	vector<bool>used;
	bimatch(int _n=0):n(_n),G(n),match(n),used(n){}
	void add_edge(int u,int v)
	{
		G[u].push_back(v);
		G[v].push_back(u);
	}
	bool dfs(int v)
	{
		used[v]=true;
		for(int u:G[v])
		
		{
			int w=match[u];
			if(w<0||!used[w]&&dfs(w))
			{
				match[v]=u;
				match[u]=v;
				return true;
			}
		}
		return false;
	}
	int count()
	{
		int ans=0;
		bool flag=true;
		fill(match.begin(),match.end(),-1);
		while(flag)
		{
			flag=false;
			fill(used.begin(),used.end(),false);
			for(int v=0;v<n;v++)if(match[v]<0&&dfs(v))ans++,flag=true;
		}
		return ans;
	}
};
#line 5 "a.cpp"
int N;
map<string,int>mp[11];
main()
{
	cin>>N;
	for(int i=0;i<N;i++)
	{
		string s;cin>>s;
		mp[s.size()][s]=i;
	}
	bimatch P(N);
	for(int i=2;i<=10;i++)for(pair<string,int>p:mp[i])
	{
		string s=p.first;
		for(int j=0;j<s.size();j++)
		{
			string t=s.substr(0,j)+s.substr(j+1);
			if(mp[i-1].find(t)!=mp[i-1].end())
			{
				P.add_edge(p.second,mp[i-1][t]);
			}
		}
	}
	cout<<P.count()<<endl;
}
accuracy: 1
time_ms: 380
memory_kb: 29292
final_rank: 4

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>
#include <unordered_map>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max() / 32 * 15 + 208;

using u64 = unsigned long long;
#include <chrono>
constexpr u64 M = (1UL << 61) - 1;
constexpr u64 POSITIVISER = M * 3;
constexpr u64 MASK30 = (1UL << 30) - 1;
constexpr u64 MASK31 = (1UL << 31) - 1;

class rolling_hash_u64 {
    static u64 get_base(){
        u64 z = (static_cast<uint64_t>((chrono::system_clock::now().time_since_epoch().count())&((1LL << 32)-1)))+0x9e3779b97f4a7c15;
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
        z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
        return z;
    }

    static u64 &B() {
        static u64 B_ = (get_base())%(M-2)+2;
        return B_;
    }

    static inline u64 calc_mod(u64 val){
        val = (val & M) + (val >> 61);
        if(val > M) val -= M;
        return val;
    }
public:
    vector<u64> hash;
    static vector<u64> &p() {
        static vector<u64> p_{1, B()};
        return p_;
    }

    static inline u64 mul(u64 x, u64 y){
        u64 a = x >> 31, b = x & MASK31, c = y >> 31, d = y & MASK31, e = b*c+a*d;
        return (a*c << 1) + b*d + ((e & MASK30) << 31) + (e >> 30);
    }

    explicit rolling_hash_u64(const string &s) {
        if(p().size() <= s.size()){
            int l = p().size();
            p().resize(s.size()+1);
            for (int i = l; i < p().size(); ++i) {
                p()[i] = calc_mod(mul(p()[i-1], p()[1]));
            }
        }
        hash.resize(s.size()+1, 0);
        for (int i = 0; i < s.size(); ++i) {
            hash[i+1] = calc_mod(mul(hash[i],B()) + s[i]);
        }
    };

    u64 get(int l, int r){
        return calc_mod(hash[r] + POSITIVISER - mul(hash[l], p()[r-l]));
    }

    static u64 val(string &s){
        if(p().size() <= s.size()){
            int l = p().size();
            p().resize(s.size()+1);
            for (int i = l; i < p().size(); ++i) {
                p()[i] = calc_mod(mul(p()[i-1], p()[1]));
            }
        }
        u64 ret = 0;
        for (int i = 0; i < s.size(); ++i) {
            ret = calc_mod(mul(ret, B()) + s[i]);
        }
        return ret;
    }
};

template<class T, bool directed>
class Dinic {
    void bfs(int s){
        fill(level.begin(),level.end(), -1);
        queue<int> Q;
        level[s] = 0;
        Q.emplace(s);
        while(!Q.empty()){
            int v = Q.front(); Q.pop();
            for (auto &&e : G[v]){
                if(e.cap > 0 && level[e.to] < 0){
                    level[e.to] = level[v] + 1;
                    Q.emplace(e.to);
                }
            }
        }
    }

    T dfs(int v, int t, T f){
        if(v == t) return f;
        for(int &i = iter[v]; i < G[v].size(); i++){
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]){
                T d = dfs(e.to, t, min(f,  e.cap));
                if(d == 0) continue;
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
        return 0;
    }
public:
    struct edge {
        int to{}; T cap; int rev{};
        edge() = default;
        edge(int to, T cap, int rev) : to(to), cap(cap), rev(rev) {}
    };

    vector<vector<edge>> G;
    vector<int> level, iter;
    Dinic() = default;
    explicit Dinic(int n) : G(n), level(n), iter(n) {}

    void add_edge(int from, int to, int cap){
        G[from].emplace_back(to, cap, G[to].size());
        G[to].emplace_back(from, directed ? 0 : cap,  G[from].size()-1);
    }


    T flow(int s, int t, T lim = INF<T>){
        T ret = 0;
        while(true) {
            bfs(s);
            if(level[t] < 0 || lim == 0) break;
            fill(iter.begin(),iter.end(), 0);
            while(true){
                T f = dfs(s, t, lim);
                if(f == 0) break;
                ret += f;
                lim -= f;
            }
        }
        return ret;
    }
};

int main() {
    int n;
    cin >> n;
    vector<string> v(n);
    unordered_map<u64, int> m;
    Dinic<int, true> G(n+2);
    for (int i = 0; i < n; ++i) {
        cin >> v[i];
        m[rolling_hash_u64::val(v[i])] = i;
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < v[i].size(); ++j) {
            string s = v[i].substr(0, j) + v[i].substr(j+1, 10);
            auto p = m.find(rolling_hash_u64::val(s));
            if(p != m.end()){
                if(v[i].size()&1) G.add_edge(i+1, p->second+1, 1);
                else G.add_edge(p->second+1, i+1, 1);
            }
        }
        if(v[i].size()&1) G.add_edge(0, i+1, 1);
        else G.add_edge(i+1, n+1, 1);
    }
    cout << G.flow(0, n+1) << "\n";
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 51360
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
using UL=unsigned int;
using LL=long long;
using ULL=unsigned long long;
#define rep(i,n) for(int i=0; i<(n); i++)

int N;
vector<string> S1;
vector<string> S0;
map<string,int> Search1;
map<string,int> Search0;

vector<pair<int,int>> J;

int fFlow = 0;

struct Edge{ int u,v,r,c; };
vector<Edge> fJ;
vector<int> fE[100002];
int fD[100002];
bool fF[100002];

void addEdge(int u, int v){
 fE[u].push_back(fJ.size());
 fJ.push_back({u,v,(int)fJ.size()+1,1});
 fE[v].push_back(fJ.size());
 fJ.push_back({v,u,(int)fJ.size()-1,0});
}

int fDFS(int p=100000, int c=1000000){
 if(p == 100001) return c;
 int f = 0;
 for(int e : fE[p]){
  if(fJ[e].c==0) continue;
  if(fD[fJ[e].v] != fD[p]+1) continue;
  if(fF[fJ[e].v]) continue;
  int res = fDFS(fJ[e].v,min(c-f,fJ[e].c));
  fJ[e].c -= res;
  fJ[fJ[e].r].c += res;
  f += res;
  if(f==c){ fF[p]=true; return f; }
 }
 fF[p]=true;
 return f;
}

bool flow(){
 static const int st = 100000;
 static const int sz = 100002;
 rep(i,sz){ fD[i] = -1; fF[i] = false; }
 queue<int> Q; Q.push(st); fD[st] = 0;
 while(Q.size()){
  int p = Q.front(); Q.pop();
  for(int e : fE[p]){
   if(fJ[e].c==0) continue;
   if(fD[fJ[e].v] != -1) continue;
   fD[fJ[e].v] = fD[p]+1;
   Q.push(fJ[e].v);
  }
 }
 int res = fDFS();
 fFlow += res;
 return res != 0;
}

int main(){

 cin >> N;
 rep(i,N){
  string S; cin>>S;
  if(S.size()%2){ Search1[S]=S1.size(); S1.push_back(S); }
  else{ Search0[S]=S0.size(); S0.push_back(S); }
 }

 rep(i,S1.size()){
  string tmp = S1[i].substr(1,string::npos);
  rep(c,tmp.size()+1){
   if(c) tmp[c-1] = S1[i][c-1];
   auto f = Search0.find(tmp);
   if(f != Search0.end()) J.push_back({ i,f->second+S1.size() });
  }
 }
 rep(i,S0.size()){
  string tmp = S0[i].substr(1,string::npos);
  rep(c,tmp.size()+1){
   if(c) tmp[c-1] = S0[i][c-1];
   auto f = Search1.find(tmp);
   if(f != Search1.end()) J.push_back({ f->second,i+S1.size() });
  }
 }

 for(auto& j:J) addEdge(j.first,j.second);
 rep(i,S1.size()) addEdge(100000,i);
 rep(i,S0.size()) addEdge(i+S1.size(),100001);

 while(flow());
 cout << fFlow << endl;

 return 0;
}
accuracy: 1
time_ms: 610
memory_kb: 71116
final_rank: 13

code_snippet: #include "bits/stdc++.h"
using namespace std;
using i64 = long long;
const i64 MOD = 1e9+7;
const i64 INF = 1e18+7;


template <typename T>
bool chmin(T& x, T y){
    if(x > y){
        x = y;
        return true;
    }
    return false;
}

template <typename T>
bool chmax(T& x, T y){
    if(x < y){
        x = y;
        return true;
    }
    return false;
}


template <typename T>
struct Dinic{
    struct Edge{
        int to, rev;
        T cap;
        Edge(int to, T cap, int rev) : to(to), rev(rev), cap(cap){}
    };

    vector<vector<Edge>> edges;
    T _inf;
    vector<T> min_cost;
    vector<int> cnt;

    Dinic(int n) : edges(n), _inf(numeric_limits<T>::max()){}

    void add(int from, int to, T cap){
        edges[from].emplace_back(to, cap, static_cast<int>(edges[to].size()));
        edges[to].emplace_back(from, 0, static_cast<int>(edges[from].size()) - 1);
    }

    bool bfs(int s, int t){
        min_cost.assign(edges.size(), -1);
        queue<int> que;
        min_cost[s] = 0;
        que.emplace(s);
        while(!que.empty() && min_cost[t] == -1){
            int x = que.front();
            que.pop();
            for(auto& ed : edges[x])
                if(ed.cap > 0 && min_cost[ed.to] == -1){
                    min_cost[ed.to] = min_cost[x] + 1;
                    que.emplace(ed.to);
                }
        }
        return min_cost[t] != -1;
    }

    T dfs(int idx, int t, T flow){
        if(idx == t)
            return flow;
        T ret = 0;
        while(cnt[idx] < edges[idx].size()){
            auto& ed = edges[idx][cnt[idx]];
            if(ed.cap > 0 && min_cost[idx] < min_cost[ed.to]){
                T d = dfs(ed.to, t, min(flow, ed.cap));
                ed.cap -= d;
                edges[ed.to][ed.rev].cap += d;
                ret += d;
                flow -= d;
                if(flow == 0)
                    break;
            }
            ++cnt[idx];
        }
        return ret;
    }

    T solve(int s, int t){
        T flow = 0;
        while(bfs(s, t)){
            cnt.assign(edges.size(), 0);
            T f = 0;
            while((f = dfs(s, t, _inf)) > 0)
                flow += f;
        }
        return flow;
    }

};


signed main(){
    int n;
    cin >> n;
    vector<string> s(n);
    for(auto& x : s)
        cin >> x;
    unordered_map<string, int> m;
    for(int i = 0; i < n; ++i)
        m[s[i]] = i;

    Dinic<int> d(n + 2);
    for(int i = 0; i < n; ++i){
        if(s[i].size() % 2 == 0)
            d.add(n, i, 1);
        else
            d.add(i, n + 1, 1);
    }

    for(int i = 0; i < n; ++i){
        for(int j = 0; j < s[i].size(); ++j){
            string t = s[i].substr(0, j) + s[i].substr(j + 1);
            if(m.find(t) != m.end()){
                int i1 = i, i2 = m[t];
                if(s[i].size() % 2)
                    swap(i1, i2);
                d.add(i1, i2, 1);
            }
        }
    }
    cout << d.solve(n, n + 1) << endl;
}
accuracy: 1
time_ms: 430
memory_kb: 55712
final_rank: 10

code_snippet: #include <bits/stdc++.h>

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}

/* copied from https://gist.github.com/MiSawa/9759784 */
/* edited by QCFium */
struct Dinic {
private:
	typedef int64_t Cap;
	static const Cap INF = 1000000000000000000;
	
	struct LCNode {
		typedef LCNode *Ptr;
		Ptr ch[2], par, min_node;
		Cap val, min_val, lazy;
		int name;
		LCNode() : par(0), min_node(this), val(INF), min_val(INF), lazy(0) {
			ch[0] = ch[1] = 0;
		}
		inline void push() {
			if (lazy == 0) return;
			val += lazy; min_val += lazy;
			for (int i = 0; i < 2; i++) if (ch[i]) ch[i]->lazy += lazy;
			lazy = 0;
		}
		inline void update() {
			push();
			if (ch[0]) {
				min_val = ch[0]->min_val + ch[0]->lazy;
				min_node = ch[0]->min_node;
			}
			if (!ch[0] || min_val > val) {
				min_val = val; min_node = this;
			}
			if (ch[1] && min_val > ch[1]->min_val + ch[1]->lazy) {
				min_val = ch[1]->min_val + ch[1]->lazy;
				min_node = ch[1]->min_node;
			}
		}
		inline void set_value(Cap v) { expose(); val = v; update(); }
		inline Cap get_value() { expose(); return val; }
		inline Ptr get_min_node_on_path() { expose(); return min_node; }
		inline void add_to_path(Cap c) { expose(); lazy += c; push(); }
		inline int state() {
			if(par && par->ch[0] == this) return -1;
			if(par && par->ch[1] == this) return +1;
			return 0;
		}
		inline void rotate() {
			Ptr p = par; p->push(); push();
			bool lr = state()+1;
			if (p->state()) p->par->ch[p->state()>0] = this;
			par = p->par;
			p->ch[lr] = ch[!lr];
			if (ch[!lr]) ch[!lr]->par = p;
			(p->par = this)->ch[!lr] = p;
			p->update(); update();
		}
		inline void splay() {
			while (state()) {
				int s = state() * par->state();
				if (s) (s == 1 ? par : this)->rotate();
				rotate();
			}
			push();
		}
		inline void expose() {
			if (!par) return;
			for (Ptr p = this; p; p = p->par) p->splay();
			for (Ptr p = this; p->par; p = p->par) p->par->ch[1] = p;
			splay();
		}
		inline void cut() {
			expose();
			if (!ch[0]) return;
			ch[0]->par = 0;
			ch[0]->push();
			ch[0] = 0;
			update();
		}
		inline void link_to(Ptr p) {
			expose();
			par = p;
		}
		inline Ptr find_root() {
			expose();
			Ptr p = this;
			while (p->ch[0]) p = p->ch[0];
			p->expose();
			return p;
		}
	};
	struct E{
		int dst;
		Cap cap;
		int rev;
		E(int dst, Cap cap, int rev) : dst(dst), cap(cap), rev(rev) {}
	};
	int n;
	std::vector<std::vector<E> > g;
	std::vector<int> level, active;
	std::vector<LCNode> lc;
	inline void unuse_edge(E &e) {
		E &ee = g[e.dst][e.rev]; int u = ee.dst;
		Cap use = ee.cap - lc[u].get_value();
		e.cap += use; ee.cap -= use;
		active[u] = false;
		lc[u].cut(); lc[u].set_value(INF);
	}
	inline void init(){
		lc.resize(n);
		active.assign(n, false);
		for (int i = 0; i < n; i++) lc[i].name = i;
	}
	Cap dfs(const int &s, const int &t) {
		std::vector<int> iter(n);
		for (int i = 0; i < n; i++) iter[i] = (int) (g[i].size()) - 1;
		Cap res = 0;

		while(1) {
			const int &u = lc[t].find_root()->name;
			if (u == s) {
				Cap f = lc[t].get_min_node_on_path()->get_value();
				res += f;
				lc[t].add_to_path(-f);
				while (1) {
					int v = lc[t].get_min_node_on_path()->name;
					Cap f = lc[v].get_value();
					if (f > 0) break;
					unuse_edge(g[v][iter[v]]);
				}
			} else {
				for (int &i = iter[u]; i >= 0; i--) {
					E &e = g[u][i], &ee = g[e.dst][e.rev]; int v = e.dst;
					if (level[u] - 1 != level[v] || ee.cap <= 0) continue;
					active[u] = true;
					lc[u].set_value(ee.cap);
					lc[u].link_to(&lc[v]);
					break;
				}
				if (active[u]) continue;
				if (u == t) break;
				level[u] = -1;
				for (auto& e : g[u]) if (active[e.dst] && iter[e.dst] == e.rev)
					unuse_edge(g[e.dst][e.rev]);
			}
		}
		for (int i = 0; i < n; i++) if (active[i]) unuse_edge(g[i][iter[i]]);
		return res;
	}

public:
	Dinic(int n) : n(n), g(n) {}
	inline void add_hen(int src, int dst, Cap cap, bool direct) {
		if (src == dst) return;
		g[src].push_back(E(dst, cap, g[dst].size()));
		g[dst].push_back(E(src, direct ? 0 : cap , g[src].size() - 1));
	}
	Cap run(int s, int t) { // O(NMlogN)
		init();
		std::vector<int> q(n);
		for (Cap flow = 0; ; ) {
			level.assign(n, -1);
			int ql = 0, qr = 0;
			level[q[qr++] = s] = 0;
			while (ql != qr && level[t] == -1) {
				int u = q[ql++];
				for (auto& e : g[u]) if (e.cap > 0 && level[e.dst] == -1)
					level[q[qr++] = e.dst] = level[u] + 1;
			}
			if (level[t] == -1) return flow;
			flow += dfs(s, t);
		}
	}
};


int main() {
	int n = ri();
	std::string s[n];
	for (auto &i : s) std::cin >> i;
	std::sort(s, s + n);
	
	std::map<std::string, int> odd, even;
	int odds = 0, evens = 0;
	for (int i = 0; i < n; i++) {
		if (s[i].size() & 1) odd[s[i]] = odds++;
		else even[s[i]] = evens++;
	}
	
	Dinic dinic(n + 2);
	int cnt = 0;
	for (auto &i : odd) {
		for (int j = 0; j < (int) i.first.size(); j++) {
			std::string cur = i.first;
			cur.erase(cur.begin() + j);
			if (even.count(cur)) dinic.add_hen(cnt + 1, even[cur] + odds + 1, 1, true);
		}
		cnt++;
	}
	cnt = 0;
	for (auto &i : even) {
		for (int j = 0; j < (int) i.first.size(); j++) {
			std::string cur = i.first;
			cur.erase(cur.begin() + j);
			if (odd.count(cur)) dinic.add_hen(odd[cur] + 1, cnt + odds + 1, 1, true);
		}
		cnt++;
	}
	for (int i = 1; i <= odds; i++) dinic.add_hen(0, i, 1, true);
	for (int i = odds + 1; i <= n; i++) dinic.add_hen(i, n + 1, 1, true);
	std::cout << dinic.run(0, n + 1) << std::endl;
	
	return 0;
}
accuracy: 1
time_ms: 470
memory_kb: 93304
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

int V; //頂点数
string name[SIZE];
map<string,int> MAP;

struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_rev_index){
		to = arg_to;
		capacity = arg_capacity;
		rev_index = arg_rev_index;
	}
	int to,capacity,rev_index;
};

vector<Edge> G[SIZE]; //グラフの隣接リスト表現
int dist[SIZE]; //sourceからの距離
int cheked_index[SIZE]; //どこまで調べ終わったか

//fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge(int from,int to,int capacity){
	G[from].push_back(Edge(to,capacity,G[to].size()));
	G[to].push_back(Edge(from,0,G[from].size()-1)); //逆辺の、初期容量は0
}

//sourceからの最短距離をBFSで計算する
void bfs(int source){
	for(int i = 0; i < V; i++)dist[i] = -1;
	queue<int> Q;
	dist[source] = 0;
	Q.push(source);

	while(!Q.empty()){
		int node_id = Q.front();
		Q.pop();
		for(int i = 0; i < G[node_id].size(); i++){
			Edge &e = G[node_id][i];
			if(e.capacity > 0 && dist[e.to] < 0){ //辺の容量が正で、かつエッジの行先に未訪問の場合
				dist[e.to] = dist[node_id]+1;
				Q.push(e.to);
			}
		}
	}
}

//増加パスをDFSで探す
int dfs(int node_id,int sink,int flow){
	if(node_id == sink)return flow; //終点についたらflowをreturn

	for(int &i = cheked_index[node_id]; i < G[node_id].size(); i++){ //node_idから出ているエッジを調査
		Edge &e = G[node_id][i];
		if(e.capacity > 0 && dist[node_id] < dist[e.to]){ //流せる余裕があり、かつsourceからの距離が増加する方法である場合
			int tmp_flow = dfs(e.to,sink,min(flow,e.capacity)); //流せるだけ流す
			if(tmp_flow > 0){ //流せた場合
				e.capacity -= tmp_flow; //流した分、エッジの容量を削減する
				G[e.to][e.rev_index].capacity += tmp_flow; //逆辺の容量を、流した分だけ増加させる
				return tmp_flow;
			}
		}
	}
	return 0;
}


//sourceからsinkへの最大流を求める
int max_flow(int source,int sink){ //source:始点 sink:終点
	int flow = 0,add;
	while(true){ //増加パスが存在する限り、流量を追加し続ける
		bfs(source);
		if(dist[sink] < 0)break; //sourceからsinkへと辿り着く残余グラフがない、つまり増加パスが無くなった場合、break
		for(int i = 0; i < V; i++)cheked_index[i] = 0;
		while((add = dfs(source,sink,BIG_NUM)) > 0){ //増加パスが見つかる間、加算
			flow += add;
		}
	}
	return flow;
}




int main(){

	scanf("%d",&V);

	int source = V,sink = V+1;

	for(int i = 0; i < V; i++){

		cin >> name[i];
		if(name[i].length()%2 == 0){

			add_edge(source,i,1);

		}else{

			add_edge(i,sink,1);
		}

		MAP[name[i]] = i;
	}

	for(int i = 0; i < V; i++){
		for(int loc = 0; loc < name[i].length(); loc++){

			string tmp = name[i];
			tmp.erase(tmp.begin()+loc);

			auto at = MAP.find(tmp);
			if(at != MAP.end()){

				if(name[i].length()%2 == 0){

					add_edge(i,MAP[tmp],1);
				}else{

					add_edge(MAP[tmp],i,1);
				}
			}
		}
	}

	V += 2;

	printf("%d\n",max_flow(source,sink));

	return 0;
}
accuracy: 1
time_ms: 770
memory_kb: 59324
final_rank: 12