[COCI2019-2020#1] Trobojnica 题解
首先,当各边颜色均相同时显然无解。接下来仅考虑存在颜色不同的边的情况。
考虑两条相邻且颜色不同的边,用一条剩余颜色的边与之形成一个三角剖分,可使原
那么可将题意转化为:每次选择两条相邻且颜色不同的边,将其合并为一条剩余颜色的边,直到剩余三条边为止,求一种可行的操作序列。
接下来我们断言,若给出的
证明:注意到上述合并操作可用异或表述(如颜色 1 与颜色 3 合并为颜色 2 可视为 1 与 3 合并为它们的异或和,即 2),每次合并后剩余所有边的异或和不变。根据题意,最终剩余三条边的颜色必然是 1,2,3 各一种,它们的异或和为
下面对满足所有边颜色异或和为
我们开一个栈来维护当前未被合并的所有边,先将第一条边压入栈。
记最后一个与第
最终,我们可以证明,所有未被合并的边一定形如
时间复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,tp,sum,cur,pos,stk[200009];
char s[200009];
inline ll read(){
ll s = 0,w = 1;
char ch = getchar();
while (ch > '9' || ch < '0'){ if (ch == '-') w = -1; ch = getchar();}
while (ch <= '9' && ch >= '0') s = (s << 1) + (s << 3) + (ch ^ 48),ch = getchar();
return s * w;
}
int main(){
n = read(),scanf("%s",s + 1);
for (ll i = 1;i <= n;i += 1) sum ^= s[i] - '0';
if (sum){
puts("NE");
return 0;
}
for (ll i = n - 1;i >= 1;i -= 1){
if (s[i] ^ s[i + 1]){
pos = i;
break;
}
}
if (!pos){
puts("NE");
return 0;
}
puts("DA");
stk[++ tp] = 1,cur = s[1] - '0';
for (ll i = 2;i <= pos;i += 1){
if (s[i] - '0' == cur){
stk[++ tp] = i;
continue;
}
ll tmp = cur;
cur = s[i] - '0';
while (tp > (i == pos)){
cur ^= tmp;
printf("%lld %lld %lld\n",stk[tp --],i + 1,cur);
}
tp += 1;
if (i == pos && tp == 2) stk[tp] = i;
}
for (ll i = pos + 2;i <= n;i += 1){
cur ^= s[n] - '0';
printf("%lld %lld %lld\n",stk[tp],i,cur);
}
ll tmp = cur ^ (s[n] - '0');
for (ll i = tp - 1;i >= 2;i -= 1){
cur ^= tmp;
printf("%lld %lld %lld\n",stk[i],n,cur);
}
return 0;
}