P10675 【MX-S1-T4】先见之明 题解注解
前情提要:本文全文都是对 @C1942huangjiaxu 题解所作的注解,加上了本人的一些思考,并将其题解中一笔带过的地方加以说明
upd: 2024.10.26 更改了一处笔误,添加了得出结论的过程。
先摆出题解中的结论:
设
如果
否则,答案即为
这个结论是怎样猜到的呢?因为我们知道,若要使选出的数之和大于等于
接下来,本文将开始证明这一个结论。
首先证明:若位置
我们从最末尾的
首先有
-
设
tmp=0 ,从大到小依次枚举a_y 。如果tmp+2^{a_y} < p_m ,则tmp\gets tmp+2^{a_y} ,否则tmp 不变。 -
进行完上述过程,可以得到一个最大的
tmp<p_m 。因为a_y 总和是要大于p_m 的,所以可以找到一个最大没有被选中的a_k ,让tmp\gets tmp+2^{a_k} ,此时tmp\ge p_m 。 -
此时观察所有小于
a_k 的位置,这些数可以被\{2^{a_y}|a_y\le p_m\} 集合构造出来,所以直接减去这些数字是没有问题的,相当于把组成这些位置的2^{a_y} 删除。 -
由此,我们就构造出来了
2^{p_m} 。
所以,
最后证明原结论
仍然可以尝试归纳,从最末尾的
首先有
我们要证明的是:
因为为了覆盖掉
我们来比较不等式两边的变化量:
左边变化量是
因为我们知道,
所以
所以,结论得证。
具体实现
本来以为证明结论之后,代码比较好写,结果发现自己竟然不会比较两个求和式的大小,所以与第一篇题解作者交流之后,参考了第一篇题解的实现方式,并加以具体说明。
我们现在要来比较
一个整体的思路是,我们先比较两者的最高位,如果最高位相同,我们就可以比较
具体地,我们设
首先,如果总和的第
否则,如果存在
如果以上两者都不满足,那么很显然,
再综合一下,我们可以得到如果这个
由此,我们就可以找到最小的不合法的
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int N=1e6+30;
int a[N];
bool use[N];
int Max[N];//用小于等于x的数字构成的最高位
int nxt[N];//全部加起来中的第一个大于等于x的位
int p[N];
bool f[N]; //f并不代表这一个位置是否满足条件,而代表 A[pi,0] 的后缀 <= P[pi,m] 的后缀
int Pow[N];
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,q;
cin>>n>>q;
set<int> st;
for(int i=1;i<=n;i++) cin>>a[i],st.insert(a[i]);
Pow[0]=1;
for(int i=1;i<=1e6+20;i++) Pow[i]=(Pow[i-1]<<1)>=mod?(Pow[i-1]<<1)-mod:(Pow[i-1]<<1);
sort(a+1,a+1+n);
int pp=1,now=-1;
for(int i=0;i<=1e6+20;i++)
{
while(a[pp]<=i&&pp<=n)
{
int t=a[pp];
while(use[t]) use[t]=0,t++;
use[t]=1,now=max(now,t);
pp++;
}
Max[i]=now;
}
nxt[1000021]=-1;
for(int i=1e6+20;i>=0;i--)
{
if(use[i]) nxt[i]=i;
else nxt[i]=nxt[i+1];
}
while(q--)
{
int m;
cin>>m;
for(int i=1;i<=m;i++) cin>>p[i];
f[m+1]=1;
int j=m+1;
for(int i=m;i;i--)
{
if(!use[p[i]]) f[i]=0;
else f[i]=f[i+1]|(i<m&&nxt[p[i+1]+1]<p[i]);
if(!f[i]&&Max[p[i]]<=p[i]) j=i;
}
long long ans=0;
for(int i=1;i<j;i++) ans+=Pow[p[i]];
if(j<=m)
{
if(st.upper_bound(p[j])==st.end()) ans=-1;
else ans+=Pow[*st.upper_bound(p[j])];
}
cout<<ans%mod<<'\n';
}
return 0;
}