20230801模拟赛
20230801模拟赛
T1三值的排序
题意
给定 \(n\) 个数,每个数为 \(1,2,3\),给这 \(n\) 个数排序。排序方法为每次交换两个数求,最小交换次数。
题解
显然可以求出三个数每个数的区间,然后考虑贪心交换次序,先把 \(1\) 区间里的 \(2\) 和 \(2\) 区间里的 \(1\) 交换,以此类推。
T2日记
题意
给定 \(N,k\),询问不超过的数中能够表示成连续的个质数之和的最大的数是多少?
题解
显然要选连续的,而答案存在随着数值增大可行性递减,所以前缀和加二分。
T3分蛋糕
题意
给定一个长度为 \(n\) 的环,每一部分有一个权值 \(a_i\),且权值互不相同,现在小 \(Y\) 和小 \(Z\),准备拿走这些权值,首先小 \(Y\) 任意拿走一个,然后从小 \(Z\) 开始,两人交替拿走剩下的值,并且被拿走的值要满足旁边一个或两个值已经被拿走。
问如果小 \(Z\) 每次拿能拿的最大权值的情况下,小 \(Y\) 能拿到权值的最大和为多少。
题解
考虑 \(dp\) 设状态为 \(f_{l,r}\) 为剩余的权值的区间为 \([l,l+1,l+2,\dots,r-1,r]\)(可能会跨过 \(n\),如 \([l,l+1,\dots,n,1,\dots,r]\))。
然后每次 \(l-1,r+1\) 进行 \(dp\),\(l\) 到 \(r\) 的长度为阶段,即拿掉的个数。枚举长度和 \(l\),\(r\) 可以直接求出来,然后 \(dp\) 式子简单。
T4都市
有 \(N\) 个数,但不给你,而是给了你 \(N\times (N-1)/2\) 个数,代表它们两两的和。
题解
题外话:考试时快想出来了,\(sb\) 了,大小比较比较个没完。
设 \(n(n-1)/2=m\)。
首先先把 \(m\) 个数排序。
显然最小的数字一定是 \(a_1+a_2\),次小的数字一定是 \(a_1+a_3\)。
然后枚举 \(a_2+a_3\),这样就可以求出来 \(a_1,a_2,a_3\)。
然后最小的是 \(a_1+a_4\),求出来 \(a_4\),删去 \(a_2+a_4,a_3+a_4\),然后以此类推。
删数可以用 \(multiset\)。
T5街灯
题意
给定 \(n\) 个数 \(a_i(1\leq a_i\leq 10^4)\),有 \(m\) 次询问,每次询问,给定 \(l,r,q,v\),问 \(\sum_{i=l}^r [a_i \equiv v\pmod p]\)
\(1\leq n,m \leq 10^5,1\leq q \leq 10^9\)
题解
震惊我了,根号分治好题呀!
先考虑 \(q\) 全部相同怎么做?将所有数字对 \(p\) 取模。问题就变成了:询问区间内等于某个数的数字有多少个?
对于每个值都开一个 vector
,将模 \(p\) 值为 \(x\) 的数字的下标都存在一起。 每次询问直接在对的vector
里面二分第一个 \(\leq l\) 的位置和第一个 \(>r\) 的位置。时间复杂度为 \(O(n+mlogn)\)。
因为 \(1\leq a_i\leq 10^4\),所以分块/根号分治。
-
当 \(p>100\),则 \(10^4\) 以内模 \(p\) 等于 \(v\) 的只有至多 \(100\) 个数(\(v,v+q,v+2q,v+3q,\dots\)),相当于每次询问都可以按照 \(q\) 相同的做法来做。
-
当 \(p\leq 100\) 时,每个数字 \(\bmod p\) 后最多也有 \(100\) 个数也可以用上面的做法求解。
代码参考:
n=read();m=read();
for(int i=1;i<=n;i++){
a[i]=read();
vt[a[i]].push_back(i);
}
while(m--){
int l=read(),r=read(),q=read(),x=read(),sum=0;
for(int i=x;i<=10000;i+=q)sum+=upper_bound(vt[i].begin(),vt[i].end(),r)-lower_bound(vt[i].begin(),vt[i].end(),l);
printf("%lld\n",sum);
}