#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")

#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace __gnu_pbds; 
typedef long long ll;
typedef long double ld;
#define INF LLONG_MAX
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MT make_tuple
#define g(a,b) get<a>(b)
#define REP(i,a,b) for(ll i = a; i<=b; i++)
#define REPI(i, a, n)  for(ll i = a; i >= (n); --i)
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update> 
#define endl "\n"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ordered_set member functions :
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set*/
 
// DISJOINT SET UNION START
ll fn(ll x,ll rn[]) // finding the component
{
    if(x==rn[x]) // Top of its component
        return x;
    else //making parent node of each node of the component the highest node
        return rn[x]=fn(rn[x],rn);
}
bool un(ll x,ll y,ll rn[],ll sz[])// union of components
{
    x=fn(x,rn);
    y=fn(y,rn);
    if(x==y)// if connected already
        return false;
    if(sz[x]<sz[y])// otherwise connectiing light to heavy by swapping
        swap(x,y);
    sz[x]+=sz[y];
    rn[y]=x;// making parent node;
    return true;
}
//DISJOINT SET UNION END

/*/SEGMENT TREE START
ll t[2][4*200000];
void build(ll a[], ll v, ll tl, ll tr,ll par) 
{
    if (tl==tr)
    {
        t[par][v] = a[tl];
    }
    else 
    {
        ll tm = (tl + tr) / 2;
        build(a, v*2, tl, tm,par);
        build(a, v*2+1, tm+1, tr,par);
        t[par][v] = max(t[par][2*v],t[par][2*v+1]);
    }
}
ll query(ll v, ll tl, ll tr, ll l, ll r,ll par) 
{
    if(tl>r || tr<l)
    {
        return 0;
    }
    if(tl>=l and tr<=r) return t[par][v];
    ll tm = (tl + tr) / 2;
    return max(query(2*v, tl, tm, l, r,par),query(2*v+1, tm+1, tr, l, r,par));
}
void update(ll v, ll tl, ll tr, ll pos, ll new_val,ll a[],ll par) 
{
    if (tl == tr) 
    {
        t[par][v]=new_val;
    }
    else 
    {
        ll tm = (tl + tr) / 2;
        if (pos <= tm)
            update(v*2, tl, tm, pos, new_val,a,par);
        else
            update(v*2+1, tm+1, tr, pos, new_val,a,par);
 
        t[par][v] = max(t[par][2*v],t[par][2*v+1]);
    }
}
//SEGMENT TREE END*/
ll gcd(ll a, ll b){if(!b)return a;return gcd(b, a % b);}
ll lcm(ll a , ll b){return (a*b)/gcd(a,b);}
ll MOD=998244353;
ll mod=1000000007;
ll power(ll x,ll y, ll p){ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}
ll inv(ll val, ll MODx = MOD) 
{
    return power(val, MODx - 2, MODx);
}
vector <ll> fac, ifac;
void preFac(ll sz) 
{
    fac.resize(sz + 1),
    ifac.resize(sz + 1);
    fac[0] = 1;
    for(int i = 1; i <= sz; i++) 
    {
        fac[i] = (i * fac[i - 1]) % MOD;
    }
    ifac[sz] = inv(fac[sz]);
    for(int i=sz-1;i>=0;i--) 
    {
        ifac[i]=((i+1)*ifac[i+1])%MOD;
    }
}
ll nCr(ll N, ll R)
{
    if(R <= N  and  R >= 0) {
        return ((fac[N] * ifac[R]) % MOD * ifac[N - R]) % MOD;
    }
    return 0;
}
vector<ll> prefix_function(string s)
{
    ll n = (ll)s.length();
    vector<ll> pi(n);
    for (ll i = 1; i < n; i++) {
        ll j = pi[i-1];
        while (j > 0 && s[i] != s[j])
            j = pi[j-1];
        if (s[i] == s[j])
            j++;
        pi[i] = j;
    }
    return pi;
}
int main() 
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    
    ll n;
    cin>>n;
    set<string> vec;
    REP(i,0,n-1)
    {
        string s;
        cin>>s;
        vec.insert(s);
    }
    set<pair<ll,string>> st[26];
    for(auto u:vec)
    {
        REP(i,0,(ll)u.size()-1)
        {
            st[u[i]-'a'].insert({(ll)u.size(),u});
        }
    }
    REP(j,0,25)
    {
        ll sz=st[j].size();
        vector<string> vv;
        if(sz>1)
        {
            for(auto u:st[j])
            {
                vv.PB(u.S);
            }
            REP(i,1,sz-1)
            {
                string s=vv[i-1];
                string t=vv[i];
                string chk=s+'*'+t;
                vector<ll> val=prefix_function(chk);
                ll flg=0;
                REP(i,s.size()+1,(ll)val.size()-1)
                {
                    if(val[i]==s.size())
                    {
                        flg=1;
                        break;
                    }
                }
                if(flg==1)
                {
                    if(vec.count(s))
                    {
                        vec.erase(vec.find(s));
                    }
                }
            }
        }
    }
    REP(i,0,25)
    {
        st[i].clear();
    }
    for(auto u:vec)
    {
        //cout<<u<<" ";
        REP(i,0,(ll)u.size()-1)
        {
            st[u[i]-'a'].insert({(ll)u.size(),u});
        }
        //cout<<endl;
    }
    REP(j,0,25)
    {
        ll sz=st[j].size();
        vector<string> vv;
        if(sz>1)
        {
            for(auto u:st[j])
            {
                vv.PB(u.S);
            }
            string s=vv[0];
            REP(i,1,sz-1)
            {
                string t=vv[i];
                if(s[0]==t.back())
                {
                    //cout<<s<<" "<<t<<endl;
                    set<char> stt;
                    ll x=0,y=t.size()-1;
                    ll cnt=0;
                    string s1="",s2="";
                    while(x<s.size() and y>=0)
                    {
                        string x1,x2;
                        x1=s1,x2=s2;
                        if(s1==s2)
                        {
                            s1+=s[x];
                            s2=t[y]+s2;
                            if(s1!=s2)
                            {
                                s1=x1,s2=x2;
                                break;
                            }
                            x++;
                            y--;
                        }
                    }
                    REP(i,x,(ll)s.size()-1)
                    {
                        stt.insert(s[i]);
                        cnt++;
                    }
                    REP(i,0,y)
                    {
                        stt.insert(t[i]);
                        cnt++;
                    }
                    if(stt.size()!=cnt)
                    {
                        //cout<<s<<" "<<t<<endl;
                        cout<<"NO"<<endl;
                        return 0;
                    }
                    else
                    {
                        vec.erase(vec.find(s));
                        vec.erase(vec.find(t));
                        string lel="";
                        string add="";
                        REP(i,0,y)
                        {
                            add+=t[i];
                        }
                        add+=s1;
                        REP(i,x,(ll)s.size()-1)
                        {
                            add+=s[i];
                        }
                        vec.insert(add);
                        s=add;
                        //cout<<s<<endl;
                    }
                }
                else if(t[0]==s.back())
                {
                    set<char> stt;
                    ll x=0,y=s.size()-1;
                    ll cnt=0;
                    string s1="",s2="";
                    while(x<t.size() and y>=0)
                    {
                        string x1,x2;
                        x1=s1,x2=s2;
                        if(s1==s2)
                        {
                            s1+=t[x];
                            s2=s[y]+s2;
                            if(s1!=s2)
                            {
                                s1=x1,s2=x2;
                                break;
                            }
                            x++;
                            y--;
                        }
                    }
                    REP(i,x,(ll)t.size()-1)
                    {
                        stt.insert(t[i]);
                        cnt++;
                    }
                    REP(i,0,y)
                    {
                        stt.insert(s[i]);
                        cnt++;
                    }
                    if(stt.size()!=cnt)
                    {
                        cout<<"NO"<<endl;
                        return 0;
                    }
                    else
                    {
                        vec.erase(vec.find(s));
                        vec.erase(vec.find(t));
                        string lel="";
                        string add="";
                        REP(i,0,y)
                        {
                            add+=s[i];
                        }
                        add+=s1;
                        REP(i,x,(ll)t.size()-1)
                        {
                            add+=t[i];
                        }
                        vec.insert(add);
                        s=add;
                    }
                }
                else
                {
                    //cout<<s<<" "<<t<<endl;
                    cout<<"NO"<<endl;
                    return 0;
                }
            }
        }
    }
    string ans="";
    for(auto u:vec)
    {
        ans+=u;
    }
    cout<<ans<<endl;

}
//try thinking from a different angle after spending some time
//PLEASE CHECK EDGE CASES!!!
