平邑一中NOIP提高集训Day 1
鸡立鹤群(致敬ytez传奇独苗syf

齐心协力这一块

Day1 模拟赛
平邑一中题质量确实不错
时间:2025/8/4 8:00 至 12:00 共4小时
难度:共5题 大概是 黄 黄/绿 绿 蓝/紫 蓝
由于手感过于差(绝对不是笔者实力过于低下呜呜呜)只打了18分呜呜呜呜
考场上。。。
先开T1
竟然是子段和!
我竟然不会子段和!
太不牛了!
开T2,暴力拿下20分
T3是好题!被硬控了!我好享受qwq
T3写了395行!我超神了!
没时间了!
T4/T5只能骗分了!
回去看T1,似乎线段树!
写!
草!没写完!
只能写暴力了!
结束了!
要挂分了!
中午在酒店。。
syf:快来快来线上分榜出了!
szh/zhc/zzl:看看我的!看看我的!
syf:额。。我草!我是rk2!!
szh/zhc/zzl:这么牛逼!!!
syf:看看你们的。。额。。zzl你20。。。
zzl:暴毙
syf:zhc你好像挂蛋了。。
zhc:暴毙
syf:szh你37分。。
szh:暴毙
szh线上榜分:0 20 17 0 0
回机房了!
得到了我的线下榜分(最终分)
szh线下榜分:0 0(谁给我T2卡掉了!) 18 0 0
总分:18分
大唐盛世

喜报:wsw把std的T3正解hack掉了!!
发挥太逊了必须改正
笔者赛后std
T1

Solution
竟然不是线段树。。
第一眼:我们需要一种支持修改和查询的数据结构。
考虑两种操作:
1.修改:希望删除后不选,由于值域非负,可以将删除改为单点修 -INF。
2.查询:最大子段和,不难想到用线段树维护:维护区间最大子段和、区间和、区间最大前缀和以及区间最大后缀和。
但是这是T1捏,线段树还是太麻烦了
第二眼:n 个元素一个个删除,且只有这一种修改,且不强制在线。
套路:时间回溯,正难则反。
将删除反过来看作添加,直接并查集维护就好了。
维护答案时,由于a中元素非负,只需要直接更新 max。
Code
#include <bits/stdc++.h>
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
int s=0,f=1;
char p=getchar();
while(p<'0'||p>'9'){
if(p=='-') f=-1;
p=getchar();
}
while(p>='0'&&p<='9'){
s*=10;
s+=p-'0';
p=getchar();
}
return s*f;
}
const int N=5e5+5;
int fa[N],n,c[N],s[N],q[N],ans[N];
int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
signed main(){
// freopen("kill.in","r",stdin);
// freopen("kill.out","w",stdout);
cin>>n;
for(int i=1;i<=n;++i){
fa[i]=i;
cin>>c[i];
}
memset(s,-1,sizeof s);
int maxn=0;
for(int i=1;i<=n;++i){
cin>>q[i];
}
for(int i=n;i>=2;--i){
int x=q[i];
s[x]=c[x];
maxn=max(maxn,s[x]);
if(s[find(x-1)]!=-1){
s[find(x-1)]+=c[x];
maxn=max(maxn,s[find(x-1)]);
fa[x]=find(x-1);
}
if(s[find(x+1)]!=-1){
s[find(x+1)]+=s[find(x)];
maxn=max(maxn,s[find(x+1)]);
fa[find(x)]=find(x+1);
}
ans[i]=maxn;
}
for(int i=2;i<=n;++i) cout<<ans[i]<<'\n';
cout<<0<<'\n';
}
T2

Solution
注意到值域很小,我们考虑与值域有关的做法。
设 \(f_i\) 表示 \(a_1..._i\) 的逆序对个数。
询问时我们只需要先计算 \(f_r-f_l−1\)然后消除 \([1,l)\) 与$ [l,r]$ 之间的贡献即可。
只需要对于每个$x $求出 \([l,r]\)中 $ x $的个数以及 \([1,l)\) 中$ >x $的个数。
这可以通过预处理二维前缀和得到。时间复杂度$ O((n + m)V)\(,其中\) V$ 为值域。
Code
#include <bits/stdc++.h>
#define PII pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
int s=0,f=1;
char p=getchar();
while(p<'0'||p>'9'){
if(p=='-') f=-1;
p=getchar();
}
while(p>='0'&&p<='9'){
s*=10;
s+=p-'0';
p=getchar();
}
return s*f;
}
int n,q;
const int N=1e6+5,M=55;
int c[N],a[N][M];
long long s[N],qzh[N],tmp[N],hzh[N];
int main(){
// freopen("interval.in","r",stdin);
// freopen("interval.out","w",stdout);
cin>>n>>q;
for(int i=1;i<=n;++i){
c[i]=read();
for(int j=1;j<=50;++j){
a[i][j]=a[i-1][j];
}
a[i][c[i]]++;
for(int j=c[i]+1;j<=50;++j){
s[i]+=a[i-1][j];
}
qzh[i]=qzh[i-1]+s[i];
}
while(q--){
int l,r;
l=read(),r=read();
for(int i=50;i>=1;--i){
tmp[i]=a[r][i]-a[l-1][i];
hzh[i]=hzh[i+1]+a[l-1][i];
}
long long ans=qzh[r]-qzh[l-1];
for(int i=1;i<=50;++i){
ans-=hzh[i+1]*tmp[i];
}
cout<<ans<<'\n';
}
return 0;
}
T3

Solution
另外,这道题我的考场思路竟跟std出奇的一致!!
(但是我只拿了18分呜呜呜
部分分还是比较足的。
考虑一下正解,手玩几组数据不难发现想到贪心,可以分类讨论一下
1.形如 101,发现如果将中间的 0 填充,有 3 个贡献。
2.形如 10 或 01,发现将的 0 填充,有 2 个贡献。
3.形如 0,将其填充获得 1 个贡献。
注意不要重复,打个标记即可。
极端情况:全0。。。
Code(18分板,这题真的很有意思,快来补题
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 7;
int read()
{
int x = 0, w = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-')
{
w = -1;
}
ch = getchar();
}
while(ch <= '9' && ch >= '0')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * w;
}
long long Qmi(int a, int b, int p)
{
if(b == 0)
{
return 1%p;
}
if(b == 1)
{
return a%p;
}
long long ans = Qmi(a, b/2, p);
ans = ans*ans%p;
if(b % 2)
{
ans = ans*a%p;
}
return ans % p;
}
bool isprime(long long x)
{
if(x <= 1)
{
return false;
}
if(x == 2)
{
return true;
}
if(x % 2 == 0)
{
return false;
}
for(int i = 3; i <= sqrt(x); i += 2)
{
if(x % i == 0)
{
return false;
}
}
return true;
}
int n, q;
string s;
int cnt;
int dn[MAXN], t[MAXN], qzh[MAXN], hzh[MAXN];
int lenn;
bool f;
int ansft;
int main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
cin>>n>>q;
cin>>s;
if(s[0] == '1')
{
f = 1;
}
for(int i = 0; i < n; i++)
{
if(s[i] == '1')
{
cnt++;
if(s[i-1] == '1')
{
if(s[i-2] != '1')
{
ansft += 2;
}
else
{
ansft += 1;
}
}
}
if(s[i] != s[i-1])
{
lenn++;
}
dn[lenn]++;
}
// for(int i = 1; i <= lenn; i++)
// {
// qzh[i] = qzh[i-1] + dn[i];
// }
//
// for(int i = lenn; i >= 1; i--)
// {
// hzh[i] = hzh[i+1] + dn[i];
// }
while(q--)
{
int x;
bool flag = 0;
for(int i = 1; i <= lenn; i++)
{
t[i] = dn[i];
}
cin>>x;
if(x == 0)
{
cout<<ansft<<endl;
continue;
}
if(x + cnt <= 1)
{
cout<<0<<endl;
continue;
}
if(x + cnt == n)
{
cout<<n<<endl;
continue;
}
if(cnt == 0)
{
cout<<x<<endl;
continue;
}
int cntc3 = 0, cntc2 = 0, cntc1 = 0;
int step = 0;
if(f)
{
for(int i = 2; i <= lenn; i+=2)
{
if(t[i] == 1)
{
if(t[i-1] == 1 && t[i+1] == 1)
{
cntc3++;
t[i-1] += 2;
t[i] += 2;
t[i+1] += 2;
step++;
continue;
}
}
if(step >= x)
{
if(step == x)
{
cout<<(3 * cntc3 + 2 * cntc2 + cntc1) + ansft<<endl;
flag = 1;
break;
}
else
{
if(cntc3 >= x)
{
cout<<(3 * x) + ansft<<endl;
}
else if(cntc3 + cntc2 >= x)
{
cout<<(3 * cntc3 + 2 * (x - cntc3)) + ansft<<endl;
}
else if(cntc3 + cntc2 + cntc1 >= x)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
flag = 1;
break;
}
}
}
if(flag)
{
continue;
}
for(int i = 2; i <= lenn; i+=2)
{
if(t[i] == 1)
{
if(t[i-1] == 1 || t[i+1] == 1)
{
if(t[i-1] == 1)
{
cntc2++;
t[i-1] += 2;
t[i] += 2;
step++;
continue;
}
if(t[i+1] == 1)
{
cntc2++;
t[i+1] += 2;
t[i] += 2;
step++;
continue;
}
}
}
if(step >= x)
{
if(step == x)
{
cout<<(3 * cntc3 + 2 * cntc2 + cntc1) + ansft<<endl;
flag = 1;
break;
}
else
{
if(cntc3 >= x)
{
cout<<(3 * x) + ansft<<endl;
}
else if(cntc3 + cntc2 >= x)
{
cout<<(3 * cntc3 + 2 * (x - cntc3)) + ansft<<endl;
}
else if(cntc3 + cntc2 + cntc1 >= x)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
flag = 1;
break;
}
}
}
if(!flag)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
}
else
{
for(int i = 1; i <= lenn; i+=2)
{
if(t[i] == 1)
{
if(t[i-1] == 1 && t[i+1] == 1)
{
cntc3++;
t[i-1] += 2;
t[i] += 2;
t[i+1] += 2;
step++;
continue;
}
}
if(step >= x)
{
if(step == x)
{
cout<<(3 * cntc3 + 2 * cntc2 + cntc1) + ansft<<endl;
flag = 1;
break;
}
else
{
if(cntc3 >= x)
{
cout<<(3 * x) + ansft<<endl;
}
else if(cntc3 + cntc2 >= x)
{
cout<<(3 * cntc3 + 2 * (x - cntc3)) + ansft<<endl;
}
else if(cntc3 + cntc2 + cntc1 >= x)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
flag = 1;
break;
}
}
}
if(flag)
{
continue;
}
for(int i = 1; i <= lenn; i+=2)
{
if(t[i] == 1)
{
if(t[i-1] == 1 || t[i+1] == 1)
{
if(t[i-1] == 1)
{
cntc2++;
t[i-1] += 2;
t[i] += 2;
step++;
continue;
}
if(t[i+1] == 1)
{
cntc2++;
t[i+1] += 2;
t[i] += 2;
step++;
continue;
}
}
}
if(step >= x)
{
if(step == x)
{
cout<<(3 * cntc3 + 2 * cntc2 + cntc1) + ansft<<endl;
flag = 1;
break;
}
else
{
if(cntc3 >= x)
{
cout<<(3 * x) + ansft<<endl;
}
else if(cntc3 + cntc2 >= x)
{
cout<<(3 * cntc3 + 2 * (x - cntc3)) + ansft<<endl;
}
else if(cntc3 + cntc2 + cntc1 >= x)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
flag = 1;
break;
}
}
}
if(!flag)
{
cout<<(3 * cntc3 + 2 * cntc2 + (x - cntc3 - cntc2 + 1)) + ansft<<endl;
}
}
}
return 0;
}
因时间原因,T4T5详见std

浙公网安备 33010602011771号