P4229 某位歌姬的故事

P4229 某位歌姬的故事

处理复杂点的 dp 题。

思路

先考虑 \(n\) 比较小的情况,把每个询问放到线段上,发现每个格子只能满足覆盖最小的限制,于是考虑将询问有效区间排序考虑。

\(f[i][j]\) 表示在 \(j\) 处放最大值满足限制 \(i\)\(j\) 之前任选,\(j\) 之后不能选最大值的方案数。

\[f[i][j]=\sum_{k\in[l_{i-1},r_{i-1}]}f[i-1][k]\times val_i^{dis(r_{i-1}+1,j-1)}\times (val_i-1)^{dis(j+1,r_i)}(j\notin [l_{i-1},r_{i-1}]) \]

其中 \(dis(l,r)\) 表示 \(l,r\) 间的距离,包括 \(l,r\) 本身。

复杂度 \(O(n^2)\),可以愉快的通过 \(5\) 个测试点。

不难发现 \(n\) 特别大但 \(q\) 的个数特别小,考虑离散化。

把询问间的点离散化成一个点,询问的端点也离散化成一个点,这样一个点就代表一段区间。

同时方程中的 \(j\) 也需要改变,因为现在 \(j\) 代表一段区间,故只要区间中有至少一个点选中最大值即可。

\[f[i][j]=\sum_{k\in[l_{i-1},r_{i-1}]}f[i-1][k]\times val_i^{dis(r_{i-1}+1,j-1)}\times (val_i-1)^{dis(j+1,r_i)}\times(val_i^{len_j}-(val_i-1)^{len_j})(j\notin [l_{i-1},r_{i-1}]) \]

将方程前缀和优化,转移复杂度 \(O(1)\),总复杂度 \(O(q^2)\)

复杂度瓶颈在离散化,使用更好的离散化方法可以做到更好的时限,不过既然能过过作者就不改了

CODE

#include<bits/stdc++.h>
using namespace std;

#define mod 998244353
#define ll long long
#define int long long

const int maxm=505,maxn=2505;

int n,Q,m,cntseg,cntval,cntl,cnt;
int lim[maxn],len[maxn],slen[maxn],val[maxn],tmplen[maxn],id[maxn],pos[maxn];

map<int,int>mp;

ll ans;
ll f[2][maxn],sf[2][maxn],inv[maxn];

struct Qry{int l,r,h;}q[maxn],tmp[maxn];

inline void clr()
{
    cnt=0,cntl=0,cntval=0,cntseg=0,ans=0;
    mp.clear();
    memset(f,0,sizeof(f));
    memset(sf,0,sizeof(sf));
    memset(inv,0,sizeof(inv));
    memset(lim,0,sizeof(lim));
    memset(len,0,sizeof(len));
    memset(slen,0,sizeof(slen));
    memset(val,0,sizeof(val));
    memset(tmplen,0,sizeof(tmplen));
    memset(id,0,sizeof(id));
    memset(pos,0,sizeof(pos));
    memset(tmp,0,sizeof(tmp));
}
inline bool cmp(Qry a,Qry b){return a.h==b.h?a.r<b.r:a.h<b.h;}
inline ll ksm(ll x,ll y)
{
    ll sum=1;
    for(;y;y/=2,x=x*x%mod) if(y&1) sum=sum*x%mod;
    return sum;
}
inline void trans(int h)
{
    if(h==1) return ;
    memset(f,0,sizeof(f));memset(sf,0,sizeof(f));
    sf[1][0]=f[1][0]=inv[0]=1;
    for(int i=1;i<=cntl;i++) sf[1][i]=sf[1][i-1],slen[i]=slen[i-1]+tmplen[i],inv[i]=ksm(ksm(h-1,slen[i]),mod-2);
    tmp[0].r=0;
    for(int i=1;i<=cnt;i++)
    {
        swap(f[1],f[0]);swap(sf[0],sf[1]);
        for(int j=0;j<=tmp[i].l-1;j++) f[1][j]=sf[1][j]=0;
        for(int j=tmp[i].l;j<=tmp[i].r;j++)
        {
            f[1][j]=f[0][j];
            if(j>tmp[i-1].r)
            {
                f[1][j]+=ksm(h-1,slen[tmp[i-1].r])*
                ksm(h,slen[j-1]-slen[tmp[i-1].r])%mod*
                sf[0][tmp[i-1].r]%mod*(ksm(h,tmplen[j])-ksm(h-1,tmplen[j])+mod)%mod;
                f[1][j]%=mod;
            }
            sf[1][j]=(sf[1][j-1]+f[1][j]*inv[j]%mod)%mod;
        }
        for(int j=tmp[i].r+1;j<=cntl;j++) sf[1][j]=sf[1][j-1],f[1][j]=0;
    }
    ans=ans*sf[1][cntl]%mod*ksm(h-1,slen[cntl])%mod;
}

signed main()
{
    // freopen("1.in","r",stdin);
    int _;
    scanf("%lld",&_);
    while(_--)
    {
        clr();
        scanf("%lld%lld%lld",&n,&Q,&m);
        cntseg=0;
        for(int i=1;i<=Q;i++)
        {
            scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].h);
            mp[q[i].l]=1,mp[q[i].r]=1;val[i]=q[i].h;
        }
        sort(q+1,q+Q+1,cmp);
        mp[1]=1,mp[n]=1;
        auto it1=mp.begin(),it2=mp.begin();
        for(it2++;it2!=mp.end();it2++,it1++) it2->second+=it1->second;
        for(it1=mp.begin(),it2=mp.begin(),it2++;it1!=mp.end();it2++,it1++)
        {
            id[++cntseg]=it1->first;len[cntseg]=1;
            if(it2!=mp.end()&&it2->first>it1->first+1) id[++cntseg]=it1->first+1,len[cntseg]=it2->first-it1->first-1;
        }
        bool flg=false;
        for(int i=1;i<=Q;i++)
        {
            q[i].l=lower_bound(id+1,id+cntseg+1,q[i].l)-id;
            q[i].r=lower_bound(id+1,id+cntseg+1,q[i].r)-id;
            int l=q[i].l,r=q[i].r;
            int mx=0;bool has=0;
            for(int j=l;j<=r;j++)
            {
                if(!lim[j]) lim[j]=q[i].h,has=1;
                else mx=max(mx,lim[j]);
            }
            if(!has&&mx<q[i].h) flg=1;
        }
        if(flg) {puts("0");continue;}
        sort(val+1,val+Q+1);cntval=unique(val+1,val+Q+1)-val-1;
        int i=1;ans=1;
        for(int j=1;j<=cntval;j++)
        {
            cntl=0,cnt=0;
            while(i<=Q&&q[i].h==val[j]) tmp[++cnt]=q[i++];
            for(int k=1;k<=cntseg;k++) if(lim[k]==val[j]) tmplen[pos[k]=++cntl]=len[k];
            for(int k=1;k<=cnt;k++)
            {
                for(;lim[tmp[k].l]!=val[j];tmp[k].l++);
                for(;lim[tmp[k].r]!=val[j];tmp[k].r--);
                tmp[k].l=pos[tmp[k].l],tmp[k].r=pos[tmp[k].r];
            }
            trans(val[j]);
        }
        for(int i=1;i<=cntseg;i++)
            if(!lim[i]) ans=ans*ksm(m,len[i])%mod;
        printf("%lld\n",ans);
    }
}
posted @ 2024-10-12 08:34  彬彬冰激凌  阅读(11)  评论(0编辑  收藏  举报