题解 [CF1342F] Make It Ascending
为啥在沈老师眼里这是一道巨大无意义题啊
首先有一个 \(O(4^n)\) 级别的暴力
令 \(f_{i, s, t}\) 为当前考虑到位置 \(i\),递增序列中上个元素由 \(s\) 组成,已知要跨过/停留在 \(i\) 的元素集合为 \(t\) 的最小操作次数
转移枚举 \(t\) 的子集作为递增序列中的一个新元素,或者将 \(i\) 扔进 \(t\)
然后发现这样光状态就是 \(3^n\) 级别的了,考虑优化
- 当状态数较大而 DP 值较小/状态数与值域相关而 DP 值与值域无关且较小时:考虑交换状态与 DP 值
那么对应到本题:
换一种 DP 方式:
令 \(f_{i, j, s}\) 为已向递增序列中加入了 \(i\) 个元素,
\(s\) 元素未加入序列时,序列中上个元素最终集中于原序列中位置 \(j\),序列中上个元素的权值最小值
复杂度 \(O(n^33^n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
pair<int, int> g[16][16][1<<15];
int a[N], f[16][16][1<<15], val[1<<15], id[16];
int pos(int s, int k) {return __builtin_popcount(s&((1<<(k-1))-1))+1;}
int dfs(int i, int j, int s) {
// cout<<"dfs: "<<i<<' '<<j<<' '<<bitset<8>(s)<<endl;
if (!i) return 0;
pair<int, int> back=g[i][j][s];
int t=back.sec^s, now=back.sec, mask=dfs(i-1, back.fir, back.sec);
now|=mask;
// cout<<"s: "<<bitset<8>(back.sec)<<' '<<bitset<8>(s)<<endl;
for (int k=1; k<=n; ++k) if (k!=j && t&(1<<(k-1))) {
printf("%d %d\n", pos(now, k), pos(now, j));
now^=1<<(k-1);
}
return mask|(1<<(j-1));
}
signed main()
{
int T=read();
while (T--) {
n=read();
for (int i=0; i<n; ++i) a[i]=read();
int lim=1<<n;
for (int i=0; i<=n; ++i) for (int j=0; j<=n; ++j) for (int s=0; s<lim; ++s) f[i][j][s]=INF;
for (int s=0; s<lim; ++s) {
val[s]=0;
for (int i=0; i<n; ++i)
if (s&(1<<i)) val[s]+=a[i];
}
f[0][0][lim-1]=0;
for (int i=0; i<n; ++i) {
for (int j=0; j<=n; ++j) {
for (int s=1; s<lim; ++s) if (f[i][j][s]!=INF) {
for (int t=s; t; t=(t-1)&s) if (val[t]>f[i][j][s]) {
for (int k=j+1; k<=n; ++k) if (t&(1<<(k-1))) {
if (val[t]<f[i+1][k][s^t]) {
f[i+1][k][s^t]=val[t];
g[i+1][k][s^t]={j, s};
}
}
}
}
}
}
for (int i=n; i; --i) {
for (int j=1; j<=n; ++j) if (f[i][j][0]!=INF) {
printf("%d\n", n-i);
dfs(i, j, 0);
goto jump;
}
}
jump: ;
}
return 0;
}