按理说,不应该想不出来,我还是太弱了,DP黑洞
首先有两个性质:
1.不会删比当前
m
e
x
mex
mex 大的数
2.要删某个数一定是一删到底,直到这个数删完
状态我是真的设计不来,要积累经验呀
f i : 考虑 0 至 i − 1 的数,即当前 m e x = i , 删完所有数的代价 f_{i}:考虑0至i-1的数,即当前 mex=i,删完所有数的代价 fi:考虑0至i−1的数,即当前mex=i,删完所有数的代价
显然状态到
0
0
0 就结束(
m
e
x
=
0
mex=0
mex=0 是无代价)
枚举删哪个数转移
c
n
t
j
cnt_j
cntj 为数字
j
j
j 的出现次数
f
i
=
{
0
(
i
=
0
)
f
j
+
j
+
(
c
n
t
j
−
1
)
∗
i
(
i
≠
0
)
f_i = \begin{cases} 0 &(i=0)\\ f_j+j+(cnt_j-1)*i &(i\ne0) \end{cases}
fi={0fj+j+(cntj−1)∗i(i=0)(i=0)
#include
#include
#include
#include
#define rep(i, j, k) for (register int i = j; i <= k; i++)
#define _rep(i, j, k) for (register int i = k; i >= j; i--)
#define _b_pct __builtin_popcount
using ll = long long;
using db = double;
using namespace std;
const int N = 1e4 + 7, M = 2e6 + 7, K = 16, INF = 1e9;
const ll inv2 = 499122177, LLF = 1e16, mod = 1e9 + 7;
int n,mex;
int a[N],cnt[N],f[N];
void pre() {
}
void init() {
memset(f,0x3f,sizeof f);
memset(cnt,0,sizeof cnt);
f[0]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(a[i]<=5200) cnt[a[i]]++;
}
for(int i=0;i<=5200;i++)
if(cnt[i]==0) {mex=i; break;}
}
void work() {
for(int i=1;i<=n;i++)
for(int j=0;j
万事从模仿开始
万事以创新开始