20251006 模拟测 总结
\(\mathcal{Preface}\)
分数 \(90+100+100+30=320\)。
挂完了,呜。
\(\mathcal{Problem \space{} A}\)
Tag:诈骗,循环。
减法可以出负数,我们希望最后的值最大,可以一开始用最小的值去减其他所有值,但是保留任意一个非最小值,最后用这任意一个非最小值去减最小值就可以了,一定是最大解。具体的,和是 \(a_2 + a_3 + \dots + a_{n-1} + a_n - a_1\),其中 \(a_1\) 是最小的数。
取余考虑保留,由于数组中的数各不相同,所以必定存在一个唯一的最小值,拿这个最小值不断去和其他值取余,最后也能保留下这个最小值,这一定是最大解。
因此两个都只需要算 \(sum\) 总和以及 \(mn\) 最小值就可以解决了。
注意特判 \(n=1\) 的情况啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!赛时没注意挂了 \(10\)pts。之后一定要注意看边界的一些特殊情况!!!!!!1111
\(\mathcal{Problem \space{} B}\)
Tag:分讨,贪心。
由于题目保证肯定可以在两次以内搞定,因此不满足回文串的位置最多也只有两处,记为 \((d_1,n-d_1+1)\) 和 \((d_2,n-d_2+1)\) 两对。如果只有一处,那么 \(d_2 = 0\),\(d_1\) 存数;而一处都没有的情况,即一开始就是回文串的话,\(d_1\) 和 \(d_2\) 当然就都不会存数了。
首先考虑一开始就是回文串的情况。显然我们手里还有两次操作,可以考虑将一些位置改成 a,优化字典序。从前往后找到这个位置对即可,至于为什么要去找,因为存在一开始就是 a 的,没必要再浪费次数修改重复的。
接着考虑只有一个位置需要修改的情况。如果 \(d_1\) 和 \(n-d_1+1\) 这两个位置中存在一个为 a 的,那么这里就只消耗了一个次数,还剩下一个次数怎么使用呢?只有当 \(n\) 是奇数的时候,我们可以考虑把最中间的那个,自己对自己的回文字符,改成 a;否则,这个次数就只能闲着啦。不过如果 \(d_1\) 和 \(n-d_1+1\) 两个位置中不存在任何一个为 a 的,那么两次就消耗完了,直接都改成 a 即可。
最后考虑有两个位置需要修改的情况,这种很简单,两个对子中都要分别选择一个字典序大的一端,把它的值改成那个较小字典序的字母,最后输出就 OK 啦。
\(\mathcal{Problem \space{} C}\)
Tag:判断质数,质数筛。
并不需要 DFS,虽然结构是棵树。
只要对读入的每条边,判断一下,如果这条边连接的两个点的点权加起来的值是质数,就让 \(ans \to ans+1\)。考虑顺序?不不不,只要定某个点为根,然后从叶子往上改就好了。
为了更快判断质数,一开始写个埃氏筛就行了,没必要写线性筛哦。
\(\mathcal{Problem \space{} D}\)
Tag:前缀和,枚举,简单思维。
考虑用 \(p_x\) 记录 \(c\) 中最多可以有多少个数字 \(x\),\(x\) 的范围是 \(1 \sim 5 \times 10^6\)。\(x\) 是 \(0\) 的可以一开始算一下,就是 \(a\) 中 \(< 10^6\) 的数字的个数。
重点在于如何计算具体 \(p\) 值。
考虑枚举 \(i\) 表示 \(b\) 中的值,然后枚举 \(j\) 为 \(i\) 的倍数并记 \(x = \frac{j}{i}\)。在这里,\(i \le 10^6\) 且 \(j \le 5 \times 10^6\)。
那么这里就有一个区间 \([j,j+i-1]\),表示在 \(b\) 值为 \(i\) 的情况下 \(a\) 中取哪个范围才能得到 \(c\) 值为 \(x\)。将原 \(a\) 值塞进桶里求前缀和,维护在区间 \([j,j+i-1]\) 中有多少个满足条件的 \(a\),加进 \(p_x\) 里。
问题在于这种方法会重复计算,一个数可能除以多个数都等于某个数,这样是行不通的,重复计算会导致数值错误。怎么办呢?只要对于每个 \(x\) 都记录一下上次 \(p_x\) 计算答案的时候的这个区间是多少,然后这次计算 \([j,j+i-1]\) 的时候判断一下,不要累加重复部分就好啦。
代码是很好写的。
n=read();
for(int i=1;i<=n;i++)a[i]=read(),s[a[i]]++;
for(int i=1;i<=5000000;i++)s[i]+=s[i-1];
for(int i=1;i<=n;i++)Ans+=(a[i]<1000000);
for(int i=1;i<=1000000;i++){
for(int j=i,x=1;j<=5000000;j+=i,x++){
LL oL=h[x].fr,oR=h[x].se;
LL nL=j,nR=min(j+i-1,5000000);
if(oR<nL)p[x]+=s[nR]-s[nL-1];
else if(oR<nR)p[x]+=s[nR]-s[oR];else;
h[x]={nL,nR};
}
}
for(int i=1;i<=5000000;i++)Ans=max(Ans,p[i]);
cout<<Ans<<"\n";
有一个 Hack,疑似能 Hack 死某些人的代码,我这里贴出来。
Input:
10
7 14 28 4000001 4000002 4000003 4000004 4000005 4000006 4000007
Answer:
10
Possible output:
9
解释一下,构造 \(b = \{ 1,2,4,571428,571428,571428,571428,571428,571428,571428\}\),可以让所有 \(c\) 值都为 \(7\)。
似乎可以 Hack 死某两位大神的赛时代码。
\(\mathcal{Summary}\)
T1 没有考虑边界情况,之后一定要注意了!!!!!!11111
T4 没有想到正解,之后要多推导一下。思维要跳出来,不要卡在一个死胡同里。
希望今天下午成绩可以好一点,呜。

浙公网安备 33010602011771号