#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
typedef std::vector<int> vector_int_t;
typedef std::string string8_t;
class TurnOnLampsDmitriyH
{
struct road_t
{
road_t(): to(0), id(0), isImp(0) {}
road_t(size_t to_, size_t id_, uint32_t isImp_): to(to_), id(id_), isImp(isImp_) {}
size_t to;
size_t id;
uint32_t isImp;
};
typedef std::vector<road_t> vector_road_t;
typedef std::vector<vector_road_t> vector_2d_road_t;
typedef std::vector<uint64_t> vector_uint64_t;
typedef std::vector<vector_uint64_t> vector_2d_uint64_t;
typedef std::set<uint64_t> set_uint64_t;
void Walk(const vector_2d_road_t& links, const string8_t& isImportant, vector_int_t& wasHere, const size_t initialId, const size_t startId, const uint64_t currentChain, vector_2d_uint64_t& switchMask)
{
switchMask[initialId][startId] = currentChain;
wasHere[startId] = 1;
const vector_road_t& link = links[startId];
for (size_t i = 0; i < link.size(); i++)
{
const size_t nextId = link[i].to;
const uint32_t isImp = link[i].isImp;
if (wasHere[nextId])
continue;
uint64_t chain = currentChain;
if (isImp)
chain |= (1ULL << link[i].id);
Walk(links, isImportant, wasHere, initialId, nextId, chain, switchMask);
}
}
uint64_t GetIntersectCount(const uint64_t x, const uint64_t y)
{
uint64_t ans = 0;
if (x == y)
return 100;
for (size_t i = 0; i < 63; i++)
{
const uint64_t d = 1ULL << i;
if ((x & d) && (y & d))
ans++;
}
return ans;
}
public:
int minimize(vector_int_t roads, string8_t initState, string8_t isImportant)
{
const size_t n = roads.size() + 1;
vector_2d_road_t links(n);
for (size_t i = 0; i + 1 < n; i++)
{
const size_t a = i + 1;
const size_t b = roads[i];
const size_t id = i;
const uint32_t isImp = isImportant[i] == '1' ? 1 : 0;
links[a].push_back(road_t(b, id, isImp));
links[b].push_back(road_t(a, id, isImp));
}
uint64_t requiredMask = 0;
for (size_t i = 0; i + 1 < n; i++)
{
if (isImportant[i] == '1' && initState[i] == '0')
{
requiredMask |= (1ULL << i);
}
}
vector_2d_uint64_t switchMask(n, vector_uint64_t(n));
for (size_t i = 0; i < n; i++)
{
vector_int_t wasHere(n);
Walk(links, isImportant, wasHere, i, i, 0ULL, switchMask);
}
set_uint64_t options;
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < n; j++)
{
options.insert(switchMask[i][j]);
}
}
options.erase(0);
uint32_t ans = 0;
uint64_t currentMask = requiredMask;
while (currentMask)
{
for (size_t i = 0; i < n; i++)
{
if (currentMask & (1ULL << i))
{
uint64_t bestMatch = 0;
uint64_t bestMask = 0;
for (set_uint64_t::const_iterator pi = options.begin(); pi != options.end(); ++pi)
{
const uint64_t nextMask = *pi;
if (currentMask & nextMask)
{
const uint64_t cnt = GetIntersectCount(currentMask, nextMask);
if (cnt > bestMatch)
{
bestMatch = cnt;
bestMask = nextMask;
}
}
}
currentMask ^= bestMask;
ans += 1;
}
}
}
return ans;
}
};
using namespace std;
#define pb push_back
#define INF 1000000000
#define L(s) (int)((s).size())
#define FOR(i,a,b) for (int _n(b), i(a); i <= _n; i++)
#define rep(i,n) FOR(i,1,(n))
#define rept(i,n) FOR(i,0,(n)-1)
#define C(a) memset((a),0,sizeof(a))
#define ll long long
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))
#define VI vector<int>
#define ppb pop_back
#define mp make_pair
#define pii pair<int,int>
#define x first
#define y second
vector<pii> sm[51];
VI mem[51];
int n;
void rec(int v, int pr) {
if (L(mem[v])) return;
if (L(sm[v]) == 1 && pr != -1) {
mem[v].resize(n + 1);
rept(i, L(mem[v])) mem[v][i] = i;
return;
}
VI cur(n + 1, 0);
rept(i, L(cur)) cur[i] = i;
rept(i, L(sm[v])) {
int w = sm[v][i].x;
if (w == pr) continue;
rec(w, v);
VI t = mem[w];
VI nt(L(t), INF);
rept(j, L(t)) {
FOR(add, -L(t), L(t)) {
if (j + add < 0 || j + add >= L(t)) continue;
if (sm[v][i].y != -1 && (j + add) % 2 != sm[v][i].y % 2) continue;
nt[j + add] = min(nt[j + add], t[j] + (add > 0 ? add : 0));
}
}
t = nt;
nt = VI(L(t), INF);
rept(j, L(t)) {
FOR(add, -L(t), L(t)) {
if (j + add < 0 || j + add >= L(t)) continue;
nt[j + add] = min(nt[j + add], t[j] + (add > 0 ? add : 0));
}
}
VI ncur(L(cur), INF);
rept(now, L(nt)) {
rept(old, L(cur)) {
if (now + old - 2 * min(now, old) < L(ncur)) {
ncur[now + old - 2 * min(now, old)] = min(ncur[now + old - 2 * min(now, old)], cur[old] + nt[now] - min(old, now));
}
}
}
cur = ncur;
}
mem[v] = cur;
}
class TurnOnLampsKADR
{
public:
TurnOnLampsKADR
()
{
for (size_t i = 0; i < 51; i++)
{
sm[i].clear();
mem[i].clear();
}
n = 0;
}
int minimize( vector <int> roads, string initState, string isImportant )
{
rept(i, 51) sm[i].clear();
n = L(roads) + 1;
rept(i, L(roads)) {
int a = roads[i];
int b = i + 1;
if (isImportant[i] == '1') {
int t = 0;
if (initState[i] == '1') t = 0; else
t = 1;
sm[a].pb(mp(b, t));
sm[b].pb(mp(a, t));
} else {
sm[a].pb(mp(b, -1));
sm[b].pb(mp(a, -1));
}
}
rept(i, 51) mem[i].clear();
int ans = INF;
rec(0, -1);
rept(i, L(mem[0])) {
ans = min(ans, mem[0][i]);
}
return ans;
}
};
#include <iostream>
#include <iomanip>
#include <ctime>
template<typename T> inline T Max(const T a, const T b) {return a > b ? a : b;}
template<typename T> inline void UpdateMax(T& a, const T b) {a = Max(a, b);}
template<typename T> inline std::ostream& operator<<(std::ostream& ost, const std::vector<T>& data)
{
for (size_t i = 0; i < data.size(); i++) { if (i != 0) { ost << ' '; } ost << data[i]; }
return ost;
}
struct stats_t
{
stats_t()
{
m_timeStart = clock();
testsPassed = 0;
maxMovesCount = 0;
}
void Print()
{
const clock_t timeStop(clock());
const unsigned long long durationMs = (((unsigned long long)1000 * (timeStop - m_timeStart) + CLOCKS_PER_SEC - 1) / CLOCKS_PER_SEC);
std::cout << "Time elapsed : " << setw(10) << durationMs / 1000 << " s " << setw(3) << durationMs % 1000 << " ms"
<< ", tests passed: " << std::setw(10) << testsPassed << ", max moves: " << std::setw(4) << maxMovesCount << std::endl;
}
clock_t m_timeStart;
uint64_t testsPassed;
int maxMovesCount;
};
stats_t g_stats;
void Test()
{
clock_t lastPrintTime(clock());
const size_t TestCount = 3000;
const size_t MaxLen = 50;
int errorsCount = 0;
for (size_t t = 0; t < TestCount; t++)
{
const size_t len = rand() % (MaxLen - 1) + 2;
vector_int_t roads(len - 1);
for (size_t i = 0; i < roads.size(); i++)
{
roads[i] = rand() % (i + 1);
}
string8_t initialState(len - 1, '0');
string8_t isImportant(len - 1, '0');
for (size_t i = 0; i + 1 < len; i++)
{
initialState[i] = rand() % 2 + '0';
isImportant[i] = rand() % 2 + '0';
}
if (rand() % 2 == 1)
string8_t(isImportant.size(), '1').swap(isImportant);
TurnOnLampsDmitriyH mySolution;
TurnOnLampsKADR othersSolution1;
const int myAns = mySolution.minimize(roads, initialState, isImportant);
const int refAns = othersSolution1.minimize(roads, initialState, isImportant);
g_stats.testsPassed += 1;
UpdateMax(g_stats.maxMovesCount, myAns);
clock_t currentTime(clock());
const unsigned long long msFromLastPrint = (((unsigned long long)1000 * (currentTime - lastPrintTime) + CLOCKS_PER_SEC - 1) / CLOCKS_PER_SEC);
if (msFromLastPrint > 1000)
{
g_stats.Print();
lastPrintTime = currentTime;
}
if (myAns != refAns)
{
errorsCount += 1;
std::cout << "Failed test case (id=" << t << ")" << std::endl;
std::cout << "Expected ans = " << refAns << ", actual ans = " << myAns << std::endl;
std::cout << len << std::endl;
std::cout << roads << std::endl;
std::cout << initialState << std::endl;
std::cout << isImportant << std::endl;
std::cout << "errorsCount = " << errorsCount << std::endl;
std::cout << std::endl;
}
}
g_stats.Print();
std::cout << "errorsCount = " << errorsCount << std::endl;
}
int main()
{
srand(0);
Test();
return 0;
}