http://cplusoj.com/d/senior/p/SS231107B
发现reverse操作会对一堆数进行修改,但如果我们只关注其中一些数呢?
假设我们已经构造好 [ 1 , i − 1 ] [1,i-1] [1,i−1],我们现在尝试构造 [ i , n ] [i,n] [i,n],我们可操作的范围是在 [ i − 1 , n ] [i-1,n] [i−1,n]
假设 i i i 在 p o s i pos_i posi,我们其实要在一个长为 n − i + 1 n-i+1 n−i+1 的序列上把位置 p o s i − i + 2 pos_i-i+2 posi−i+2 移到位置2,这个东西很dp。于是我们就设 d p ( x , y ) dp(x,y) dp(x,y) 表示长为 x x x,从 y y y 移到2的最小步数。
注意这个dp不一定需要最优的策略,也就是说我们可以贪心决策。我们可以枚举最后一个格子是否被选,或者选多少。然后我们贪心希望 y y y 每次往前移。(往后移可能也可行,但我们找的是范围内的最优解,所以不需要)
然后这样子还是会略超,所以我们可以考虑继续完善贪心。我们可以维护从前往后指针 x x x 和从后往前指针 y y y,取最优的取移。
#include
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 3010
//#define M
//#define mo
int rev[13][100010];
void revese(int n, int l) {
for(int i=0; i<n; ++i) rev[l][i]=((rev[l][i>>1]>>1)|((i&1)<<l-1));
}
void Min(int &a, int b) {
a=min(a, b);
}
struct Fe {
int x, lstx, lsty, opx, opy;
Fe operator = (const int a) {
x=a; return (*this);
}
}f[N][N], g[N][N];
Fe Min(Fe a, Fe b) {
return a.x<b.x ? a : b;
}
int n, m, i, j, k, T;
int a[N], pos[N];
vector<pair<int, int> >G;
void init() {
int x, y, l, t;
for(x=0; x<N; ++x) for(y=0; y<N; ++y) f[x][y].x=g[x][y].x=1e9;
for(x=3; x<=n; ++x) {
for(y=2; y<x; ++y) {
f[x][y]=f[x-1][y];
if(y==2) f[x][y]=0;
for(k=1; (1<<k)<=x; ++k) {
l=x-(1<<k)+1;
if(l>=y) continue;
t=y-l;
// debug("[%d][%d] %d %d\n", x, y, k, t);
if(rev[k][t]<t && f[x][l+rev[k][t]].x+1<f[x][y].x) {
f[x][y].x=f[x][l+rev[k][t]].x+1;
f[x][y].lstx=x; f[x][y].lsty=l+rev[k][t];
f[x][y].opx=l; f[x][y].opy=k;
}
}
// debug("f[%d][%d]=%d\n", x, y, f[x][y].x);
}
}
for(x=3; x<=n; ++x) {
for(y=x-1; y>=2; --y) {
g[x][y]=g[x-1][y-1];
if(y==x-1) g[x][y]=0;
for(k=1; (1<<k)<=x; ++k) {
if((1<<k)<y) continue;
t=y-1;
if(rev[k][t]>t && g[x][rev[k][t]+1].x+1<g[x][y].x) {
debug(">>> %d || %d %d 【】 %d\n", k, rev[k][t], t, g[x][rev[k][t]+1].x);
g[x][y].x=g[x][rev[k][t]+1].x+1;
g[x][y].lstx=x; g[x][y].lsty=rev[k][t]+1;
g[x][y].opx=x; g[x][y].opy=k;
}
}
debug("g[%d %d] = %d\n", x, y, g[x][y].x);
}
}
}
void work(int l, int k) {
for(int i=0; i<(1<<k); ++i)
if(i<rev[k][i]) swap(a[i+l], a[rev[k][i]+l]);
}
void remake_pos() {
for(int i=1; i<=n; ++i) pos[a[i]]=i;
}
signed main()
{
freopen("butterfly.in", "r", stdin);
freopen("butterfly.out", "w", stdout);
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// T=read();
// while(T--) {
//
// }
n=read(); m=read();
for(i=0; i<=12; ++i) revese(1<<i, i);
for(i=1; i<=n; ++i) a[i]=read();
remake_pos();
init();
int x, y;
x=2; y=n-1;
while(x<y) {
if(pos[x]==x) { ++x; continue; }
if(pos[y]==y) { --y; continue; }
int len=y-x+1;
int s1=f[len+2][pos[x]-x+2].x;
int s2=g[len+2][pos[y]-x+2].x;
debug("=== %d %d\n", s1, s2);
if(s1<s2) {
debug("oper 1\n");
auto t=f[len+2][pos[x]-x+2];
while(t.opx) {
G.pb({t.opx+x-2, t.opy}); work(t.opx+x-2, t.opy);
t=f[t.lstx][t.lsty];
}
++x;
}
else {
debug("oper 2\n");
auto t=g[len+2][pos[y]-x+2];
while(t.opx) {
G.pb({y+2-t.opx, t.opy}); work(y+2-t.opx, t.opy);
t=g[t.lstx][t.lsty];
}
--y;
}
remake_pos();
for(int i=1; i<=n; ++i) debug("%d ", a[i]); debug("\n");
}
for(int i=1; i<=n; ++i) debug("%d ", a[i]); debug("\n");
printf("%d\n", G.size());
for(auto t : G) printf("%d %d\n", t.fi, t.se);
return 0;
}