def equilibre_reccurEtendue(texte, n, ind):
    res=([],0)
    if longueur(texte)<=n: #si la longueur du texte est inférieur à la longueur de la ligne
        res=([texte],0,'infini',0) #alors pas besoin de le découper, et on ignore le déséquilibre
        MEMO.add_etendue(ind,res[0],res[1],res[2],res[3])
    else :
        curr=0
        s='infini'
        longtext=longueur(texte[0:1])
        while longtext<=n:
            reccur=MEMO.get_etendue(ind+curr+1)
            if reccur==-1:
                reccur=equilibre_reccurEtendue(texte[curr+1:],n,ind+curr+1)
                MEMO.add_etendue(ind+1,reccur[0],reccur[1],reccur[2],reccur[3])
            c=reccur[2]
            l=reccur[3]
            if min(longtext,c)==longtext:
                c=longtext
            if min(longtext,l)==l:
                l=longtext                
            s1=l-c
            if min(s1,s)==s1:
                s=s1
                res=([texte[0:curr+1]]+reccur[0],s,c,l)
            curr+=1
            longtext=longueur(texte[0:curr+1])
    return res
def equilibreEtendue(texte, n):  
    global MEMO
    MEMO=Memo()
    for i in range (len(texte)-1,-1,-1):    #Pour i allant de l'indice du dernier mot au premier
        if longueur(texte[i:])<=n:
            res=([texte[i:]],0,'infini',0)
        else:
            curr=0
            deseq='infini'
            longtext=longueur(texte[i:i+1])
            while longtext<=n:
                suite=MEMO.get_etendue(i+curr+1)
                c=suite[2]
                l=suite[3]
                if min(longtext,c)==longtext:
                    c=longtext
                if min(longtext,l)==l:
                    l=longtext                
                deseq_bis=l-c
                if min(deseq,deseq_bis)==deseq_bis: #on notera que la fonction min a été surchargée pour
                                                    #considérer 'infini' comme l'infini
                    deseq=deseq_bis
                    res=([texte[i:i+curr+1]]+suite[0],deseq,c,l)
                curr+=1
                longtext=longueur(texte[i:i+curr+1])
        MEMO.add_etendue(i,res[0],res[1],res[2],res[3])
    return res
def equilibre_reccur(texte, n, ind):
    res=([],0)
    if longueur(texte)<=n: #si la longueur du texte est inférieur à la longueur de la ligne
        res=([texte],0) #alors pas besoin de le découper, et on ignore le déséquilibre
        MEMO.add(ind,res[0],res[1])
    else :
        curr=0
        s='infini'
        while longueur(texte[0:curr+1])<=n:
            reccur=MEMO.get(ind+curr+1)
            if reccur==-1:
                reccur=equilibre_reccur(texte[curr+1:],n,ind+curr+1)
                MEMO.add(ind+1,reccur[0],reccur[1])
            s1=blancLigne(texte[0:curr+1],n)+reccur[1]
            if min(s1,s)==s1:
                s=s1
                res=([texte[0:curr+1]]+reccur[0],s)
            curr+=1
    return res
def equilibreVar(texte, n):
    global MEMO
    MEMO=Memo()
    for i in range (len(texte)-1,-1,-1):    #Pour i allant de l'indice du dernier mot au premier
        if longueur(texte[i:])<=n:
            res=([texte[i:]],0)        
        else:
            curr=0
            deseq='infini'
            while longueur(texte[i:i+curr+1])<=n:
                suite=MEMO.get(i+curr+1)
                deseq_bis=variance([texte[i:i+curr+1]]+suite[0])
                if min(deseq,deseq_bis)==deseq_bis: #on notera que la fonction min a été surchargée pour
                                                    #considérer 'infini' comme l'infini
                    deseq=deseq_bis
                    res=([texte[i:i+curr+1]]+suite[0],deseq)
                curr+=1
        MEMO.add(i,res[0],res[1])
    return res
def fusionTextsMinMax(text1, text2, stringLength):
    #print "Try to fusion"
    fusionedString = text1[-1][:] + text2[0][:]
    if(possibleString(fusionedString, stringLength)):
        #print "Fusioned string: ", fusionedString
        #print "is possible"
        fusionedLength = longueur(fusionedString)
        #print "with length", fusionedLength
        if(len(text1)>0):
            text1.pop()
        if(len(text2)>0):
            text2.pop(0)
    
        resultText = text1 + [fusionedString] + text2
        #print "minmax for fusioned text:", longShortDistance(resultText)


        return True, longShortDistance(resultText), resultText
    else:
        #print "Fusion impossible"
        return False,[0,0],[]
def equilibrium(words, stringLength): #O(n^4)
    wordsCount = len(words)
    #Initialise par maxInt
    
    #Les matrices qui contiennent la longueur de ligne de taille maximale/minimale dans le texte
    maxMatrix = [[sys.maxint for _ in xrange(wordsCount)] for _ in xrange(wordsCount)]
    minMatrix = [[0 for _ in xrange(wordsCount)] for _ in xrange(wordsCount)]

    #La matrice qui contient les sous-textes pour chaque pas de programmation dynamique
    #Initialisee par listes vides
    stringMatrix = [[[] for _ in xrange(wordsCount)] for _ in xrange(wordsCount)]

    #Le parcours des diagonales commenceant d'element [0][0]
    k = 0;
    m = wordsCount;
    for s in range(0, m): #O(n^2/2)
        for i in range(k, wordsCount):
            j = i-k
            #print "###########################"
            #print "## Working with case",i,j,"##"
            #print "###########################"

            #Remplissage des diagonales
            if(i==j):
            #Remplissage des diagonales principales par mots seuls et poids des lignes avec un seul mot
            #    print "Filling main diagonal case"
                
                minMatrix[i][j] = longueur([words[i]])
                maxMatrix[i][j] = longueur([words[i]])
                
                stringMatrix[i][j] = [[words[i]]]
                
            #   print "String in case", stringMatrix[i][j]
            #   print "Min value", minMatrix[i][j]
            #print "Max value", maxMatrix[i][j]
            else:
                #Remplissage des autres diagonales

                #Essayons de construire une nouvelle partie de texte a partir des construites les plus optimales
                #On peut concatener soustextes ou fusionner la derniere ligne de premier soustexte et premier ligne de deuxieme soustexte
                #en les concatenant si c'est possible
                column = j+1
                for row in range(j, i):
                    #Concatenations des soustextes
                    #print "Working with case ", row,j, "with text", stringMatrix[row][j], "difValue:", maxMatrix[row][j]-minMatrix[row][j]
                    #print "and case", i, column," with text", stringMatrix[i][column], "difValue:", maxMatrix[row][j]-minMatrix[row][j]
                    d = max([maxMatrix[row][j], maxMatrix[i][column]]) - min([minMatrix[row][j], minMatrix[i][column]])
                    #print "Max-Min for concatenation", d
                    #print "Current value", maxMatrix[i][j]-minMatrix[i][j]

                    if(d < maxMatrix[i][j] - minMatrix[i][j]):
                        #print "Now Min = ", minMatrix[i][j]
                        maxMatrix[i][j] = max([maxMatrix[row][j], maxMatrix[i][column]])
                        #print "Max = ", maxMatrix[i][j]
                        stringMatrix[i][j] = stringMatrix[row][j] + stringMatrix[i][column]
                    #print "New string = ", stringMatrix[i][j]

                    #Essai de fusion des soustextes
                    fusion = fusionTextsMinMax(stringMatrix[row][j][:], stringMatrix[i][column][:], stringLength)
                    if(fusion[0] and fusion[1][0] - fusion[1][1] < maxMatrix[i][j] - minMatrix[i][j]):
                        maxMatrix[i][j] = fusion[1][0]
                        minMatrix[i][j] = fusion[1][1]
                        stringMatrix[i][j] = fusion[2]
                    #print "Placed string", fusion[2]

                    column = column + 1

        k = k+1;
        m = m-1;

    #print "Result string:", stringMatrix[wordsCount-1][0]
    #print "Result dif:", maxMatrix[wordsCount-1][0] - minMatrix[wordsCount-1][0]
    return stringMatrix[wordsCount-1][0], maxMatrix[wordsCount-1][0] - minMatrix[wordsCount-1][0]