你将如何解决一个问题:
给定的整数序列可以分解成这样的部分 他们每个人都是回文。考虑序列34,45,34,56,34。 这可以分为3个回文序列,分别为34,45,34 构成第一个,56个构成第二个和34个构成 第三。它也可以在每个5个回文序列中被打破 包含一个数字。因此,可能有许多不同的方法 将给定序列分解为回文序列。我们想 确定最小数量C,使得给定序列可以 分解成C回文序列。
我的解决方案是这样的:找到阵列的最大回文(最大长度的回文),除了这个最大回文之外,取其余的数据,并尝试找到它的最大回文等,同时增加数量回文数量。
这是我到目前为止所做的:
#include <algorithm>
#include <iostream>
#include <vector>
#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;
int calc(vector<ll> A, int N) {
int i = N;
vector <ll> t1, t2;
while (i >= 0) {
t1 = vector <ll> (A.begin(), A.begin()+i);
t2 = vector <ll> (t1.rbegin(), t1.rend());
if (t1 == t2) return i;
i--;
}
return 0;
}
int main() {
int N;
ll x;
cin >> N;
vector <ll> A(N);
for (int i = 0; i < N; i++) {
cin >> x;
A[i] = x;
}
int temp = calc(A,N);
int c = 0;
while (temp != 0) {
A = vector <ll> (A.begin()+temp, A.end());
N = (int)A.size();
temp = calc(A, N);
c++;
}
cout << c << endl;
}
然而,我得到3个测试用例错了。稍后意识到我的程序为测试用例输出4而不是2:N = 8,{2,1,2,1,2,3,2,1}它的回文需要{2,1,2,1,2} },{3},{2},{1},而它应该是{2,1,2},{1,2,3,2,1}。如果我反转向量并计算两者之间的最小答案,我将得到正确的答案2对于此测试用例但对于Codechef上的其他人我仍然得到2个测试用例错误,可能是因为我得到错误的原因相同。
无论如何,知道如何改进这个吗?
关于codechef问题的链接:https://www.codechef.com/ZCOPRAC/problems/ZCO15001来自正在进行的比赛,但比赛只是在印度举行的Zonal Computing Olympiad的练习赛。
答案 0 :(得分:1)
这是动态编程的典型问题。您可以使用O(N ^ 2)
复杂度轻松解决此问题,其中N
是输入字符串的大小。
首先,你可以预先计算O(N ^ 2)
复杂度的所有回文,如果[i, j]
中的子串O(1)
是回文,那么就应该回答(让它成为你的练习)。 / p>
然后你可以计算数组dp
,其中dp[i]
是子串[0, i]
的答案。要查找dp[i]
您需要执行的操作:dp[i] = min(dp[i], dp[j] + 1)
适用于所有j
j < i
和子串[j + 1, i]
为回文结构。在这里你使用palindromes预先计算来检查[j + 1, i]
中是否存在子串O(1)
回文。 dp[0]
当然是1
。
答案是dp[N - 1]
。
P.S。所有索引都是从0开始的。