SRM439 div1 medium

メモ化再帰
難しくて解説みた。

#include <string>
#include <vector>
#include <cstdio>
#include <cstring>

using namespace std;
typedef long long LL;

LL DP[(1<<13)][2][15][15];

class PalindromePhrases 
{
	public:

		int n;
		vector<string> words;

		bool isPalindome(string s)
		{
			for(int i=0;i<s.size();i++)
				if(s[i]!=s[s.size()-1-i])
					return false;
			return true;
		}

		LL rec(int left,int isLeft,int id,int len)
		{
			LL &r=DP[left][isLeft][id][len];
			if(r!=-1)
				;
			else if(isLeft)
			{
				r=0;
				int pos=words[id].size()-len;
				string s=words[id].substr(pos);
				if(isPalindome(s))
					r++;
				for(int next=0;next<n;next++)
					if(left & (1<<next))
						if(len<words[next].size())
						{
							int i;
							for(i=0;i<len;i++)
								if(words[id][pos+i]!=words[next][words[next].size()-1-i])
									break;
							if(i==len)
								r+=rec(left^(1<<next),0,next,words[next].size()-i);
						}
						else
						{
							int i;
							for(i=0;i<words[next].size();i++)
								if(words[id][pos+i]!=words[next][words[next].size()-1-i])
									break;
							if(i==words[next].size())
								r+=rec(left^(1<<next),1,id,len-i);
						}
			}
			else
			{
				r=0;
				int pos=len-1;
				string s=words[id].substr(0,len);
				if(isPalindome(s))
					r++;
				for(int next=0;next<n;next++)
					if(left & (1<<next))
						if(len<words[next].size())
						{
							int i;
							for(i=0;i<len;i++)
								if(words[id][i]!=words[next][len-1-i])
									break;
							if(i==len)
								r+=rec(left^(1<<next),1,next,words[next].size()-i);
						}
						else
						{
							int i;
							for(i=0;i<words[next].size();i++)
								if(words[id][pos-i]!=words[next][i])
									break;
							if(i==words[next].size())
								r+=rec(left^(1<<next),0,id,len-i);
						}
			}
			return r;
		}

		LL getAmount(vector <string> _words) 
		{
			words=_words;
			n=words.size();

			memset(DP,-1,sizeof(DP));
			LL ans=0;
			for(int i=0;i<n;i++)
				ans+=rec(((1<<n)-1)^(1<<i),1,i,words[i].size());
			return ans;
		}
};