2022.9.22———HZOI【CSP-S模拟9】YO寄
点击查看代码
的题好像是
今天的随只因化(暗藏玄只因)爆零了,赛后很难受,总共只得到了分的好成绩
下午讲题发现意外的听懂了,并且发觉怎么这么水,我真是个
当然讲的没听懂(
T1 最长上升子序列, T2 独特序列, T3 最大GCD, T4连续子段
一道构造题
首先把不是a[i]
的扔到队列里,注意是升序
然后从贪心地使字典序最小,当然要先加入a[i]
再贪心,为了使得a[]
就是最后的,要满足要加入的一个q[L]
小于a[i]
。因为如果大于的话如果他比a[i+1]
要小,那么就使得更长了,如果比a[i+1]
要大,那么显然不满足字典序最小的要求。不存在等于的情况(废话)。
最后要对a[K]
进行一下特殊判断,因为a[K]
并不一定等于,这也是我赛事挂成的原因。
-
如果
a[K]
比队尾大,那么显然直接让队尾到队头降序扔到a[K]
的后面就行了。 -
如果
a[K]
比队尾小,那么如果直接再按刚才的降序直接扔,显然会变长,所以让队尾到队列中第一个比a[K]
大的数都降序扔到a[K]
的前面,剩下的再扔到a[K]
的后面就行了。
T1
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 200005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
int n, K, L, R;
char is[N];
int a[N], ans[N], q[N];
void work(){
cin >> n >> K;
for (re i = 1 ; i <= K ; ++ i)
{cin >> a[i]; is[a[i]] = true;}
L = 0, R = -1;
for (re i = 1 ; i <= n ; ++ i)
if (is[i] == false)
q[++ R] = i;
for (re i = 1 ; i <= K-1 ; ++ i){
ans[++ ans[0]] = a[i];
if (q[L] < a[i] and L <= R)
ans[++ ans[0]] = q[L ++];
}
/*for (re i = 1 ; i <= n ; ++ i)
cout << ans[i] << _;
Endl;*/
if (a[K] < n)
while (q[R] > a[K] and L <= R)
ans[++ ans[0]] = q[R --];
ans[++ ans[0]] = a[K];
/*for (re i = 1 ; i <= n ; ++ i)
cout << ans[i] << _;
Endl;*/
while (L <= R)
ans[++ ans[0]] = q[R --];
for (re i = 1 ; i <= n ; ++ i)
cout << ans[i] << _;
Endl;
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
一个简单的一维。
设为转移到,并且必选的方案数,初始值。
考虑如何转移。
考虑这样一个数列:
在搞到第二个的时候,值只能由上一个到当前位置转移,用柿子表达出来就是
就是上一个
的意思。
考虑为什么从到不转移。
从到的方案,对于再添上一个而言和添上一个而言是等同的,因为就和一样嘛只不过位置不同,但是这样一来就不满足唯一性了。
就比如序列是合法的(转移到目前而言),归属于;而是不合法的,因为转移到目前发现有超过一个的。
考虑为什么要转移。
对于序列,本身不合法,但是当转移的时候要填上他,因为序列是合法的。
但是转移完之后要删去,因为向这样的序列是不合法的。
最后求一个前缀和就行了,可以用树状数组维护。
T2
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 200005
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
一维dp是吧
我想想,树状数组
树状数组
好久不用了
一维dp
哎哎,我啥时候能学会dp
flag:学完线性筛就去打背包dp
*/
long long n;
long long a[N], f[N], plc[N], C[N<<2];// 树状数组要开多大来着
#define lowbit(x) ((x) & (-(x)))
inline void Update(long long k, long long ed, long long w){
while (k <= ed){
C[k] = (C[k] + w + P) mod P;
k += lowbit(k);
}
}
inline long long Query(long long k){
long long res(0);
while (k != 0){
res += C[k];
if (res >= P)
res -= P;
k -= lowbit(k);
}
return res;
}
inline void work(){
cin >> n;
for (re i = 1 ; i <= n ; ++ i)
cin >> a[i];
/*for (re i = 2 ; i <= n ; ++ i){
f[i] = 1;
if (plc[i] != 0)
Update(1, n, -f[plc[i]]);
f[i] += Query(i);
if (f[i] >= P)
f[i] -= P;
Update(
}*/
f[1] = 1; plc[a[1]] = 1; Update(1, n, 1);
for (re i = 2 ; i <= n ; ++ i){
f[i] = Query(i-1);
if (plc[a[i]] != 0){
f[i] = (f[i] - Query(plc[a[i]]-1) + P) mod P;
Update(plc[a[i]], n, -f[plc[a[i]]]);
}
else
f[i] ++;
if (f[i] >= P)
f[i] -= P;
plc[a[i]] = i;
Update(i, n, f[i]);
}
cout << Query(n) << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
这个题我上来一眼丁真认定为场切题,发颠分解了个质因数发现用没有,之后又尝试二分发现假了,然后就搞了随只因化
然后喜提。
乐
正解很简单,分两种情况
设为中最大值
若
显然要先让所有的达到,此时就是,然后贪心地使不断并判断当前值能否达到。
可以直接写成一个柿子dsu
设为所有达到所需要的和,那么最后答案即为。
这玩意不难理解吧,已经是基础了,所有的值都是了这时候所有同时他们的也就会同时,也就是那个柿子
若
这就有意思了
考虑枚举他们的公共因子。那么如果让每个拥有该因子,根据显然的贪心策略,每个肯定是变成比他大的第一个的的倍数。
那么达到该状态所需要消耗的+1次数
就是
这样做是的。
考虑如何优化。
我们可以把升序排序一下,然后枚举也就是的倍数,二分找到他应该在数组中的位置,减去上一个倍数所在位置,然后直接累加。根据调和级数这样做是只带一个的。
所以就拆掉了一个变成了。总时间复杂度为(与值域同阶)。
然后可以拆一下原柿子,就直接把拆出来,也就是求一下的总和,不用在刚才二分的过程中减来减去,最后直接减就完了。
然后这题就做完了,总体思路十分简单,代码实现也不难,确实可以算是场切题
但是我这个赛时怎么就没想到。。。
T3
#include <iostream>
#include <algorithm>
#include <cmath>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 300005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
枚举倍数
调和级数
蛮巨的
分两种情况,
算了在草稿纸上胡了一遍就不在这里写了
*/
long long n, K, mx, first_step, sum, final_ans;
long long a[N];
inline void work(){
cin >> n >> K;
for (re i = 1 ; i <= n ; ++ i)
{cin >> a[i]; mx = MAX(mx, a[i]); sum += a[i];}
for (re i = 1 ; i <= n ; ++ i)
first_step += (mx-a[i]);
if (first_step <= K)
{goto Another_Me;}
sort(a+1, a+n+1);
for (long long factor = mx, plc, res, ed, lst ; factor >= 1 ; -- factor){
res = -sum; ed = ceil((double)mx / factor); lst = 0;
for (long long bs = 1 ; bs <= ed ; ++ bs){
plc = upper_bound(a+1, a+n+1, bs*factor) - a - 1;
res += bs * factor * (plc-lst);
// cerr << factor << _ << lst << _ << plc << _ << bs << _ << res << '\n';
lst = plc;
}
// cerr << '\n' << '\n';
if (res <= K)
{final_ans = factor; break;}
}
cout << final_ans << '\n';
return ;
Another_Me:{
final_ans = mx + (K-first_step)/n;
cout << final_ans << '\n';
}
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
(其实我也不是特别明白)
(开始大量转发)
观察K的数据范围 不难想到状压。
设 为选到的数的集合为 的最少移动次数。
先预处理一下每个状态选了几个数(有多少个)。
转移的话就是看看这个数有没有在集合里:如果不在,就加上这个数所移动的步数(逆序对数)。
每种集合还要加上 集合向右平移的步数 或者 让还没有选的数集体向左平移,二者取 。
———迪神
T4
#include <iostream>
#include <cstring>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 300005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
int n, K, S;
int a[N], f[(1<<16) + 5], cnt[(1<<16) + 5];
/*
“浮华的二进制。”
*/
#define lowbit(x) ((x) & (-(x)))
inline void work(){
cin >> n >> K; S = (1 << K) - 1;
for (re i = 1 ; i <= n ; ++ i)
cin >> a[i];
for (re i = 0, x ; i <= S ; ++ i){
x = i;
while (x != 0)
cnt[i] ++, x ^= lowbit(x);
}
/*Dendl;
for (re i = 0 ; i <= S ; ++ i)
cerr << cnt[i] << _;
Dendl;*/
memset(f, 0x5f, sizeof(f));
f[0] = 0;
for (re i = 1, x ; i <= n ; ++ i){
x = 1 << (a[i]-1);
for (re s = S ; s >= 0 ; -- s){
f[s|x] = MIN(f[s|x], f[s] + cnt[s&(-x)]);
f[s] += MIN(cnt[s], K-cnt[s]);
}
// cerr << f[S] << '\n';
}
cout << f[S] << endl;
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
(图我给扔到酰铧里了)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现