【考后】CSP-S模拟9
我要再这么颓下去就无了。
A. \(\color{black}{\textrm{LIS to Original Sequence}}\)
题解
就是构造。
怎么构造?
这么构造!
先插入 \(a_i\) ,再插入一个小于 \(a_i\) 且在没有取过的数字中最小的数 \(\left(i \in \left[1,k\right)\right)\) 。(如果没有则跳过)
最后把剩下的数倒序输出。
显然,我们保证了序列 \(A\) 是我们构造的 \(P\) 的一个 \(\texttt{LIS}\) 。
其实字典序最小也是比较显然的,因为每次都插入了最小的数,并且不能再插入一个第二小的数了,否则 \(\texttt{LIS}\) 就变了。
#include <iostream>
const int N = 2e5+10;
int n, k;
int buf[N];
int a;
int main() {
scanf("%d %d",&n,&k);
register int j = 1;
for(register int i = 1;i < k;++i) {
scanf("%d",&a);
printf("%d ",a);
buf[a] = true;
while(buf[j])
++j;
if(j < a) {
printf("%d ",j);
buf[j] = true;
while(buf[j])
++j;
}
}
for(register int i = n;i >= j;--i)
if(!buf[i])
printf("%d ",i);
putchar(10);
return 0;
}
B. \(\color{black}{\textrm{Unique Subsequence}}\)
题解
每次如果数 \(a_i\) 第一次出现,就正常转移 : \(dp_i = \sum\limits_{j = 1}^{i-1}dp_{j}+1\) 。
否则只从 \(prev_{a_i} \sim i-1\) 转移,并删去 \(prev_{a_i}\) 。
#include <iostream>
const int moyn = 998244353;
const int N = 2e5+10;
int n;
int tree[N];
void modify(int pos,int val) {
for(;pos <= n;pos += pos&-pos) {
tree[pos] = tree[pos]+val;
if(tree[pos] >= moyn)
tree[pos] -= moyn;
}
}
int query(int pos) {
int res = 0;
for(;pos;pos -= pos&-pos) {
res += tree[pos];
if(res >= moyn)
res -= moyn;
}
return res;
}
int buf[N];
int val[N];
int ans;
int main() {
scanf("%d",&n);
for(register int i = 1;i <= n;++i) {
int a, f;
scanf("%d",&a);
if(buf[a]) {
f = ans-query(buf[a]-1)+moyn;
if(f >= moyn)
f -= moyn;
modify(buf[a],moyn-val[a]);
ans = (ans-val[a]+moyn);
if(ans >= moyn)
ans -= moyn;
} else
f = ans+1;
modify(i,f);
ans += f;
if(ans >= moyn)
ans -= moyn;
buf[a] = i;
val[a] = f;
}
printf("%d\n",ans);
return 0;
}
C. \(\color{black}{\textrm{Maximize GCD}}\)
题解
挺好搞的。
-
\(k\) 可以使所有值达到 \(\max\left\{a\right\}\) , \(ans = \max\left\{a\right\}+\left\lfloor\dfrac{k-\sum_{i = 1}^{{{n}}}\max\left\{a\right\}-a_i}{n}\right\rfloor\)
-
否则枚举每一个 \(x \in \left(1,\max\{a\}\right)\) ,发现当且仅当 \(\sum\limits_{i = 1}^{n}x-a_i \bmod x \le k\) 时成立。于是可以每 \(\left(k\cdot x,(k+1)\cdot x\right]\;,\;\left(k \in \left[0,\frac{\max\{a\}}{x}\right]\right)\) 一组进行求解。
#include <iostream>
#include <random>
#define llt long long int
const int N = 3e5+10;
llt n, ans = 1;
llt a[N], k, del_sum;
llt max_a = 0;
llt buf_pre[N], sum_pre[N];
int main() {
scanf("%lld%lld",&n,&k);
for(register int i = 1;i <= n;++i) {
scanf("%lld",&a[i]);
if(a[i] > max_a)
max_a = a[i];
++buf_pre[a[i]];
sum_pre[i] += (llt)a[i];
}
for(register int i = 1;i <= n;++i)
del_sum += max_a-a[i];
if(k >= del_sum) {
std :: cerr << "here\n";
printf("%lld\n",max_a+(k-del_sum)/n);
} else {
for(register int i = 1;i < N;++i) {
sum_pre[i] += sum_pre[i-1];
buf_pre[i] += buf_pre[i-1];
}
// std :: cerr << k << std :: endl;
for(register int i = 2;i < N;++i) {
llt l = 1LL;
llt r = (llt)i;
llt res = 0LL;
while(l < N) {
llt tmp_1 = buf_pre[std :: min(r,N-1LL)]-buf_pre[l-1];
llt tmp_2 = sum_pre[std :: min(r,N-1LL)]-sum_pre[l-1];
res += r*tmp_1-tmp_2;
l += i;
r += i;
}
if(res <= k)
ans = i;
}
printf("%lld\n",ans);
}
return 0;
}
D. \(\color{black}{\textrm{Pure Straight}}\)
题解
咕咕咕
#include <iostream>
#include <cstring>
int n, k, m;
int a[201];
int dp[1<<16];
int main() {
scanf("%d %d",&n,&k);
for(register int i = 1;i <= n;++i)
scanf("%d",&a[i]);
m = (k+1)>>1;
memset(dp+1,0x3f,((1<<k)-1)*sizeof(int));
for(register int i = 1;i <= n;++i)
for(register int j = (1<<k)-1;~j;--j) {
if(!((j>>(a[i]-1))&1))
continue;
int true_counter = __builtin_popcount(j);
int del_nowbit = j^(1<<(a[i]-1));
int upper_counter = __builtin_popcount(j>>a[i]);
if(true_counter < m)
dp[j] = std :: min(dp[j],dp[del_nowbit]+upper_counter-i+true_counter-m);
else if(true_counter > m)
dp[j] = std :: min(dp[j],dp[del_nowbit]+upper_counter+i-true_counter+m);
else
dp[j] = std :: min(dp[j],dp[del_nowbit]+upper_counter+(k&1 ? 0 : -1)*i);
}
printf("%d\n",dp[(1<<k)-1]);
return 0;
}