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;
}
posted @ 2024-08-21 13:40  ax_by_c  阅读(19)  评论(0)    收藏  举报