跳的贪心方式是唯一的,考虑操作的贪心:
一左一右交替跳一定比同侧优——左跳时贪心选右端点最小的,右跳时贪心选左端点最大的。
枚举第一步是左/右跳分别 O ( n ) O(n) O(n)模拟出答案后取 max \max max即可。
数据范围的明示: 4 N 2 → N 2 4N^2 \to N^2 4N2→N2
对于每种 D D D,不能同时选的点之间连边,必然构成一张二分图。
两种 D D D,选 1 2 ⋅ 1 2 = 1 4 \frac12·\frac12=\frac 14 21⋅21=41部分的点必然有解,双重染色后找最大的一部分即可。
设每条边被经过次数是 c n t i cnt_i cnti,答案上界= ∑ min ( 2 , c n t i ) \sum \min(2,cnt_i) ∑min(2,cnti)
大胆猜想一定能达到上界,一个经典的构造证明:
每次删去一个叶子结点 x x x,若 x x x的父边 c n t ≤ 1 cnt\leq 1 cnt≤1,则不需要定向处理;否则取出其中两条路径 ( x , y ) , ( x , z ) (x,y),(x,z) (x,y),(x,z),为使答案达到上界强制这条条路径反向,假设两条路径的交为 ( x , a ) (x,a) (x,a),则这一段都达到了上界,剩下需要决策的实际上为 ( y , z ) (y,z) (y,z)这条路径。不断删点,就构造出了一组可行解。
暴力模拟可证复杂度线性 系列
从高位到低位每位重复模拟 K K K遍处理: ( 1 , 1 ) (1,1) (1,1)进位时遇到两个数同一位不相同的情况( ( 0 , 1 ) , ( 1 , 0 ) (0,1),(1,0) (0,1),(1,0))直接暴力进位,否则遇到连续的一段 ( 0 , 0 ) (0,0) (0,0)可以直接移过去,因为从低位的影响不会超过高位,所以不会遇到 ( 1 , 1 ) (1,1) (1,1)。
栈维护下标从大到小(当前位置)的 ( 0 , 1 ) , ( 1 , 0 ) (0,1),(1,0) (0,1),(1,0),复杂度均摊是线性的(不会证,可以感性理解为每弹两次栈最多只会压入一个数对)
code from sigongzi
#include
#define fi first
#define se second
#define pii pair
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 2000005
#define mp make_pair
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
struct node {
int id,par;
}sta[MAXN],tmp[MAXN];
int N,M,K,top,cnt,ns[MAXN],nt[MAXN],as[MAXN],at[MAXN];
char s[MAXN],t[MAXN];
void Solve() {
read(N);read(M);read(K);
scanf("%s",s + 1);scanf("%s",t + 1);
reverse(s + 1,s + N + 1);reverse(t + 1,t + M + 1);
for(int i = 1 ; i <= N ; ++i) ns[i] = s[i] - '0';
for(int i = 1 ; i <= M ; ++i) nt[i] = t[i] - '0';
int T = max(N,M);
for(int i = T ; i >= 1 ; --i) {
if(ns[i] == 1 && nt[i] == 1) {
int op = K,pos = i,x = 3;cnt = 0;
while(top) {
if(x == 3) {
if(op >= sta[top].id - pos) {
op -= sta[top].id - pos;
pos = sta[top].id;
tmp[++cnt] = (node){pos,x ^ sta[top].par};
x = x & sta[top].par;
}
else break;
}
else if(x != 0){
if(sta[top].id == pos + 1) {
pos = sta[top].id;
if(x ^ sta[top].par) x = 3;
else x = x & sta[top].par;
}
else break;
}
else break;
--top;
}
if(x != 0 && x != 3) {
++pos;
tmp[++cnt] = (node){pos,x};
}
else if(x) {
pos += op;
as[pos] = at[pos] = 1;
}
for(int j = cnt ; j >= 1 ; --j) sta[++top] = tmp[j];
}
else {
if(ns[i] || nt[i]) {
sta[++top] = (node){i,ns[i] << 1 | nt[i]};
}
}
}
for(int i = 1 ; i <= top ; ++i) {
as[sta[i].id] = (sta[i].par >> 1) & 1;
at[sta[i].id] = sta[i].par & 1;
}
int c = T + K;
while(as[c] == 0) --c;
for(int i = c ; i >= 1 ; --i) {out(as[i]);}
enter;
c = T + K;
while(at[c] == 0) --c;
for(int i = c ; i >= 1 ; --i) {out(at[i]);}
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}