模拟赛总结合集

2024

2024.4.20

T1

对于图上费用问题,可以考虑重构图。

T2

有颜色限制时,可以考虑次短路。

2024.3.30

T2

简化题意,完全图匹配的本质是任意两点都可匹配。考虑排序后 dp,\(dp(i,j,0/1)\) 表示选到 \(i\),已经匹配 \(j\) 组,第 \(i\) 个选/不选时最小匹配。有 \(dp(i,j,0)=\min(dp(i-1,j,0),dp(i-1,j,1)),dp(i,j,1)=dp(i-1,j,0)+a_{i}-a_{i-1},ans=\min(dp(n,m,0),dp(n,m,1))\)

2024.3.23

T2

打完部分分可以考虑推广。

比如树上重心可以推广到树上 \(k\) 长重链,加一个维度即可。

T3

大模拟尽量把题意弄懂再开打。(主要是出题人的锅)。

2024.3.2

T2

二分答案时,注意实现答案可能会改变。即每次判断二分的解是否可行时,需要重新考虑解。

T4

考虑简化答案。基环树中的环的答案可先行求出。然后加上枝条的影响。

2024.1.20

T4

题意

给定 \(0\le l,r\le 10^9\),求

\[\sum_{i=l}^r\sum_{j=l}^r i\operatorname{xor}j \]

正解

分每一位考虑,

\[\begin{aligned} &\sum_{i=l}^r\sum_{j=l}^r i\operatorname{xor}j\\ =&\sum_{k=0}^{\log}\sum_{i=l}^r\sum_{j=l}^r (i[k]\ne j[k])\times 2^k \end{aligned} \]

数位 dp,搜出第 \(k\) 位为 \(0\) 的数量 \(x\),第 \(k\) 位为 \(1\) 的数量 \(y=(r-l+1)-x\),答案即为

\[\sum_{k=0}^{\log}x\times y\times 2^k \]

#include <iostream>
using namespace std;
typedef long long ll;
constexpr int mod=1e9+7,N=40;
int mem[N][2],a[N];
#define now mem[i][small]
int dfs(int i,int k,int small=false)// cnt 0
{
if(~now)return now;
if(!i)return now=1;
now=0;
if(i==k)now=dfs(i-1,k,small||a[i]);// only 0
else now=dfs(i-1,k,small||a[i])+(small||a[i]?dfs(i-1,k,small):0);// 0/1
return now;
}
int calc(int x,int k)
{
if(x==-1)return 0;
int cnt=0;
while(x)a[++cnt]=x&1,x>>=1;
fill(*mem,*mem+(N<<1),-1);
return dfs(cnt,k+1);
}
int main()
{
int T,l,r,ans;
ll tmp;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&l,&r);
ans=0;
for(int k=0;(1<<k)<=r;k++)
{
tmp=calc(r,k)-calc(l-1,k);
tmp=tmp*((r-l+1)-tmp)%mod;
ans=(ans+(tmp<<k)%mod)%mod;
}
printf("%d\n",(ans<<1)%mod);
}
return 0;
}

2024.1.13

T2

题意

\(m\) 个方格,其中 \(n\) 个蹦床,第 \(i\) 个可以向右跳 \(l_i\) 格。

\(1\) 号方格开始,求到 \(m\) 的方案数,\(\bmod{10^9+7}\)

考场解法

树状数组解决。

正确写法:

constexpr int N=1145141,p=1000000007;
int n,m;
namespace bit// range add, point get
{
int t[N];
#define lb (x&(-x))
inline void add(int x,int y){for(;x<N;x+=lb)t[x]=((t[x]+y)%p+p)%p;}// 错误:t[x]=(t[x]+y+p)%p;
inline void add(int l,int r,int y){add(l,y),add(r+1,-y);}
inline int get(int x){int res=0;for(;x;x-=lb)res=((res+t[x])%p+p)%p;return res;}// 错误:res=(res+t[x]+p)%p;
}// namespace bit

取模不规范,亲人两行泪。

正解

前缀和。当然树状数组也可以。

T4

题意

\(n\),权值 \(v_i\),颜色 \(c_i\),取任意多组 \([l_i,r_i],r_{i-1}<l_i<r_i\),最大化

\[\sum_i\sum_{j=l[i]}^{r[i]}v_j \]

正解

dp+优化,

#include <iostream>
using namespace std;
typedef long long ll;
constexpr int N=1145141;
constexpr ll INF=1e18;
int n,k;
ll c[N],v[N],dp[N],j[N];
int main()
{
freopen("poker.in","r",stdin);
freopen("poker.out","w",stdout);
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)scanf("%lld",c+i),j[c[i]]=-INF;
for(int i=1;i<=n;i++)scanf("%lld",v+i),v[i]+=v[i-1];
for(int i=1;i<=n;i++)
{
// dp[i]=dp[i-1];
// for(int j=1;j<i;j++)if(c[j]==c[i])
// {
// dp[i]=max(dp[i],dp[j-1]+(v[i]-v[j-1]));
// }
//! dp[i]=max(dp[i],(dp[j-1]-v[j-1])+v[i]));
dp[i]=max(dp[i-1],j[c[i]]+v[i]);
j[c[i]]=max(j[c[i]],dp[i-1]-v[i-1]);
}
printf("%lld",dp[n]);
return 0;
}

2023

2023.12.30

原题洛谷题单

T1

题意

给定一棵树,节点带权 \(v\),初始为 \(0\)

\(q\) 个多测,每次给定点集 \(S\),表示 \(i\in S,v_i\gets 1\)

每次操作可子树 \(\operatorname{xor} 1\)(翻转)。求最少操作次数使树中所有点权为 \(0\)

  • \(1\sim 6\)(Force):\(n,q\le 10^3\)
  • \(7\sim 8\)(A):\(|S|=1\)
  • \(9\sim 11\)(B):\(S\) 内点不相邻。
  • \(12\sim 14\)(C):链,\(f_i=i-1\)
  • \(15\sim 16\)(D):\(f_i=\operatorname{random}[1,i-1]\)

考场解法

8:32 开打

如果 \(i \in S\),必然有操作奇数个在祖先。

同时若 \(i\) 操作后为 \(1\),必然要以 \(i\) 为根操作。

dfs,额外记录祖先操作次数 \(o\),如果 \(o+[u \in S]\) 为奇数,要翻转。

以上 \(O(nq)\)。可拿 \(1\sim 6\)

8:42 开打 \(O(n^2)\)

9:09 打完,测完,\(30\text{ pts}\) 到手。

9:13 特 A,\(|S|=1\),显然需要反转以 \(u\) 为底的子树。

同时需要反转 \(u\) 的所有儿子的子树。

答案为 e[u].size()\(+1\)

9:20 打完,测完,\(40\text{ pts}\) 到手。

特 B,无直接连接。

9:37 寄。

特 C,链。

9:49 B 又懂了。打!

10:16 B、C 都打完了,样例除 \(7\) 外全过。

xor:\(70\text{ pts}\)

Note:
B:无直接连接可直接拆成 \(|S|\) 个 A 性质,一个一个做,这样翻转完 \(u\) 的子树再翻转所有儿子的子树,可做到只翻转 \(u\)

C:合并连通块,答案即为连通块(同属于 \(S\))数量 \(\times 2\),注意最后一个特判减 \(1\)

分数

\(70\text{ pts}\)

正解

其实很近了,将 C 中链扩展为树,对树中连通块缩点,统计缩点后 \(S\) 中(多个缩成一个只算一个点)节点度数。

T2

考场解法

  • subtask 1:直接判,输出 int(a[1]>a[2])
  • subtask 2:不会(其实应该是搜,没时间想)。
  • subtask 3:
namespace t3
{
bool check(){int x=abs(a[1]);for(int i=2;i<=n;i++)if(x!=abs(a[i]))return false;return true;}
void solve()
{
int cnt=1;
ll ans=0ll;
for(int i=1;i<=n;i++)
{
if(a[i]<0)
{
ans+=ll(abs(cnt-i));
cnt+=2;
}
}
printf("%lld",ans);
}
}
  • subtask 4:
namespace t4
{
bool check(){int x=n>>1;for(int i=1;i<=x;i++)if(a[i]>0||(-a[i])!=a[i+x])return false;return true;}
void solve(){n>>=1;printf("%lld",(1ll*(n-1)*n)>>1ll);}
}
  • subtask 5、6:不会。

分数

\(45\text{ pts}\)

T3、T4

未看题、过难。

2023.12.23

T3

题意

长度为 \(n\) 的序列 \(a\),合并果子,代价为两堆重量的积,求所有情况总代价之和。

考场解法&正解

容易发现顺序不重要。

\[\sum_{i=2}^{n}\cfrac{i\times (i-1)}{2} \]

种,相乘即可。

代码:

#include <iostream>
using namespace std;
typedef long long ll;
constexpr int N=114514,mod=998244353;
ll n,a[N];
int main()
{
scanf("%lld",&n);
ll pre=0,times=0,k=1;
for(int i=1;i<=n;i++)
{
scanf("%lld",a+i);
(times+=(a[i]*pre))%=mod;
(pre+=a[i])%=mod;
}
for(ll i=n;i>1ll;i--)
{
(k*=(i*(i-1)>>1ll))%=mod;
}
// for(int i=2;i<=n;i++)(k*=i)%=mod;
// (k=k*k/n)%=mod;
printf("%lld",(times*k)%mod);
return 0;
}

2023.12.16

T1

题意

前缀 \(\operatorname{mex}\)

考场解法&正解

#include <iostream>
#include <bitset>
using namespace std;
constexpr int N=114514,A=1e9+7;
int n,ans;
bitset<A> cnt;
int main()
{
freopen("mex.in","r",stdin);
freopen("mex.out","w",stdout);
scanf("%d",&n);
for(int i=1,a;i<=n;i++)
{
scanf("%d",&a);
cnt[a]=true;
while(cnt[ans])ans++;
printf("%d ",ans);
}
return 0;
}

T2

题意

给三个集合,各选一个数,求最小的绝对值差(\(|a-b|+|a-c|+|b-c|\))。

考场解法

枚举 \(2\) 个,二分 \(1\) 个。

正解

枚举 \(1\) 个,二分 \(2\) 个。

T3

题意

钉针有一匹小马叫珍珠。为了赢下不久以后举行的小镇策马比赛,钉针在家里定制了两个长度为 \(n\) 米的跑道,让雪豹和珍珠在上面赛跑。

跑道是一个长度为 \(n\) 的字符串,每个字符只可能是 \(\texttt{E}\)\(\texttt{W}\)\(\texttt{S}\)\(\texttt{N}\) 之一,分别表示(从当前的位置向)东、西、南、北延长 \(1\) 米。保证相邻的两个字符不会一个是 \(\texttt{S}\) 一个是 \(\texttt{N}\),也不会一个是 \(\texttt{E}\) 一个是 \(\texttt{W}\)

珍珠和雪豹会同时站在跑道的起点,钉针则对他们同时下达指令:选择东、西、南、北之一的方向,让珍珠和雪豹同时向这个方向走 \(1\) 米。如果珍珠或雪豹当前的位置不存在这个方向的跑道,它就会在原地不动。如果有,即使它已经到达了终点,也会倒回去 \(1\) 米。

钉针想知道,在这种条件下,珍珠和雪豹能不能都到达终点。

正解

如果倒回去,必然存在 \(s\) 后缀为 \(t\) 后缀的取反。
暴力判即可。

T4

题意

也就是说,你有一个 \(n\) 个点,\(m\) 条边的无向简单连通图,点权初始全部为 \(0\)。接下来有 \(q\) 次操作或询问,分别是以下三种中的一种:

  1. \(1~p~v\),表示对 \(p\) 点和与 \(p\) 点直接相连的所有点进行点权 \(+v\) 的操作。
  2. \(2~p~v\),表示对 \(p\) 点和与 \(p\) 点直接相连的所有点进行点权 \(\times v\) 的操作。
  3. \(3~p\),你需要回答此时 \(p\) 点点权对 \(998244353\) 取模的值。

考场解法

暴力 \(1e3\)+bfs 序树转序列线段树维护 \(4e5\)

线段树调用参数炸了,\(20\text{ pts}\)(暴力分)。

赛后调试日志:

20:03 开订

long long

20:12 订完了,交

Killed: Segmentation fault

md

20:19 开大,特判越界,交

20:27 试试 bfs

咦~ 还没 WA,先 RE 了

20:29 再试试

一样的

鉴定为 bfs

20:30 开大 bfs 相关数组

理论上不会 RE 的啊

20:32 康康 inputs

input 时 RE???

弱智

并不

到 bfs 都没问题

wssb| 调试用 &&0 忘关

忘关就是开啦

md

编译一下发现忘打 = temp line 140)

弱智

20:44 交!

File Error fxxk

20:45 试试 modify

CE FXXK

20:47 交,RE,取之,modify

查 modify 罢

20:48 逝世 build

WA

看来是 modify 的问题

20:58 对之前的 40 pts,交

21:04 判

终于……

判松点试试

忽然懂了

有些节点是叶子,没有孩子,导致修改 [l,r]=[beg[u],end[u]]=[0,0]。

然后永远修不到,导致 RE。

放宽所有越界判断

21:12 交

60 pts
说明全是线段树黑箱外部原因。

放宽外部判断到底线。

60 pts

缩紧seg数组

60 pts

与seg无关

看来它是好人


Part II 分块优化

牛逼!!!

只能说榜1dalao太秀了

21:29 开订暴力

21:43 订完

21:49 忘了样例里有 *

正解

分块 \(1e4\)+bfs 序树转序列线段树维护 \(4e5\)

放上代码

2023.12.9

T1

题意

给定长度为 \(n\) 的数列 \(a\),求对于每个 \(i\) 对应的 \(j\)\(ans_i=\max\{j\}-i-1\)\(ans_i<0\) 时输出 \(ans_i\gets-1\)。其中 \(j\) 满足 \(a_j<a_i\)

考场解法&正解

排序后显然 \(a_i\) 左侧的 \(a_j\) 都满足 \(a_j<a_i\)。于是求前缀的 下标最大值 即可。

错误:选择以 \(a_i\) 升序排序。
没有考虑 \(a_i=a_j\) 的情况。此时 \(j\) 不合法。故要加一个关键字 \(id\) 升序。

\(a_i=a_j\) 时,若 \(i<j\)\(a_i\) 排前。这样就可以过滤 \(a_i=a_j\)

分数

\(75\text{ pts}\)

T2

题意

简化后:给出 \(s_{i,j}\in \{\texttt{a}\cdots\texttt{z}\}\)\(i\le n\le 500,j\le m\le 500\)),要求改成:

  • 每行只有两种不同字符。
  • 相邻字符不同。

求改的次数(代价)的最小值。

正解

要求即:

  • 每行交错两个,设为 \(a_i,b_i\)
  • 上下两行 \(a_i\ne a_{i-1},b_i\ne b_{i-1}\)

明显状压:\(dp(i,a,b)\) 改到第 \(i\) 行(包含),改为 \(a_i=a,b_i=b\) 的最小代价。

\[dp(i,a,b)=\min_{\mathclap{a\ne c\land a\ne b\land b\ne d\land c\ne d}}\{dp(i-1,c,d)\}+cost(i,a,b) \]

分数

\(10\text{ pts}\)

T3

题意

给定一个长度为 \(n\) 的序列 \(a\),一共有 \(m\) 个操作。
每次操作的内容为:给定 \(x,y\),序列中所有 \(x\) 会变成 \(y\)

代码:

int ans = 2147483647;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[i] == a[j])
ans = std::min(ans, j - i);
}
}
std::cout << ans << std::endl;

请在每次修改后输出代码运行的结果。

考场解法

离散化+ set

正解

暴力,由于修改后 \(a\) 中不同颜色数量单调不增,所以答案为 \(1\) 后一直输出 \(1\) 即可。

以上解法玄学复杂度。忘记是从哪里看来的了。真·正解已丢失。

分数

\(100\text{ pts}\)

T4

题意

洛谷 P4381 [IOI2008] Island
即拆基环树,使直径最短。边带权。

考场解法

分数据:\(O(n^2)\)+特殊性质:环。

日常 long long

正解

紫题,拱出去!

疑似树形 dp。

分数

\(30\text{ pts}\)

2023.12.2

T1

题意

给定一个数字,求写出它所需的笔画数。(\(4,5\)\(2\) 画,其他 \(1\) 画。)
\(n\le 10^{101}\)

考场解法&正解

显然输入字符串后遍历每位统计。

分数

\(100\text{ pts}\)

T2

丢失。但 \(100\text{ pts}\)

T3

题意

\(n\times m\)\(n,m\le 500?\))的迷宫,给定走迷宫的策略:若前方是障碍,右转。

给定 \(q\) 个坐标,回答从此位置向 \(4\) 个方向分别能否走出迷宫。

考场解法

反着搜,从边界的位置反向搜出能走出迷宫所有状态(位置、方向)。

明显复杂了,也不好实现,打炸了。

没时间打暴力,输出 NNNN 骗分,一分没得。

分数

\(0\text{ pts}\)

T4

题意

给定两个数组 \(a,b\)\(|a|=n,|b|=m\)\(n,m\le 5000?\)。对于每个 \(i\in[1,n]\),选择 \(a_i\)\(b_i\),记 \(sum\) 为其和。

要求尽量连续选择:若上一种(选择 \(a_i\)\(b_i\))连选了 \(k\) 个,这次切换后要至少连选 \(2k\) 个。

\(\min\{sum\}\)

考场解法

\(dp(i,j,k)\)\(i\in[1,n],j\in\{0,1\},k\in[,i]\))表示选完到第 \(i\) 个,最后选了 \(a_i/b_i\)\(j=0/1\)),连续 \(k\) 个,最小 \(sum\)

\[dp(i,j,k)=\min_{2l\le k}\{dp(i,\lnot j,l)\}+\sum_{\mathclap{l=i-k+1}}^{i} a_l \]

复杂度 \(O(n^3)\)

正解

加上前缀最小值优化即可。

posted @   Po7ed  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示