CF1728G
自己想的但是做法怎么和官方题解一样啊???
从静态问题入手,考虑状压。设 \(f_{i,S}\) 表示使用前 \(i\) 个灯,已经照亮点的集合为 \(S\) 的方案数。
假设我们已经得到了 \(f\),考虑如何回答询问。注意到将一盏灯所覆盖的点的编号状压只会有 \(m\) 种不同的结果,所以可以直接枚举。设枚举的状态为 \(S\),其补集为 \(T\),则答案为 \(\sum_{T\in P}f_{n,P}\)。
发现最后是超集求和的形式,使用高维前缀和即可解决,问题是如何求 \(f\)。
考虑容斥,设 \(g_{i,S}\) 表示使用前 \(i\) 个灯,已经照亮点的集合为 \(S\) 的子集的方案数。若求得 \(g\),则使用高维差分即可求得 \(f\)。
求 \(g\) 则较为简单,每个状态只会对超集产生贡献。于是枚举每一盏灯,发现一盏灯的状态都是包含关系,所以使用高维前缀积和逆元即可解决。
由于 \(m\) 比较小,为了方便实现的时候直接进行了排序。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll ksm(ll a,ll b,ll p){
a=a%p;
ll r=1;
while(b){
if(b&1){
r=r*a%p;
}
a=a*a%p;
b>>=1;
}
return r%p;
}
ll inv(ll x){
return ksm(x,mod-2,mod);
}
const int N=2e5+5;
const int M=20;
const int S=(1<<16)+5;
int len,n,m,q;
int a[N];
struct point{
int val,id;
}pos[M];
int cmppos;
bool cmp(point x,point y){
return abs(x.val-cmppos)<abs(y.val-cmppos);
}
ll f[S];
int main(){
scanf("%d %d %d",&len,&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%d",&pos[i].val);
pos[i].id=i;
}
int mxst=(1<<m)-1;
for(int i=0;i<=mxst;i++){
f[i]=1;
}
for(int i=1;i<=n;i++){
cmppos=a[i];
sort(pos+1,pos+1+m,cmp);
int cur=0,st=0,nxt;
if(abs(pos[1].val-a[i])!=0){
f[0]=f[0]*abs(pos[1].val-a[i])%mod;
}
for(int j=1;j<=m;j++){
cur=abs(pos[j].val-a[i]);
st|=1<<(pos[j].id-1);
if(j==m||cur!=abs(pos[j+1].val-a[i])){
nxt=abs(pos[j+1].val-a[i]);
if(j==m){
nxt=len+1;
}
f[st]=f[st]*inv(cur)%mod*nxt%mod;
}
}
}
for(int j=0;j<m;j++){
for(int i=0;i<=mxst;i++){
if(i&(1<<j)){
f[i]=f[i]*f[i^(1<<j)]%mod;
}
}
}
for(int j=0;j<m;j++){
for(int i=0;i<=mxst;i++){
if(i&(1<<j)){
f[i]=(f[i]-f[i^(1<<j)]+mod)%mod;
}
}
}
for(int j=0;j<m;j++){
for(int i=0;i<=mxst;i++){
if(i&(1<<j)){
f[i^(1<<j)]=(f[i^(1<<j)]+f[i])%mod;
}
}
}
scanf("%d",&q);
int p;
while(q--){
scanf("%d",&p);
cmppos=p;
sort(pos+1,pos+1+m,cmp);
ll ans=0;
int cur=0,st=0,nxt;
if(abs(pos[1].val-p)!=0){
ans=(ans+f[mxst]*abs(pos[1].val-p)%mod)%mod;
}
for(int j=1;j<=m;j++){
cur=abs(pos[j].val-p);
st|=1<<(pos[j].id-1);
if(j==m||cur!=abs(pos[j+1].val-p)){
nxt=abs(pos[j+1].val-p);
if(j==m){
nxt=len+1;
}
ans=(ans+f[mxst^st]*(nxt-cur)%mod)%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号