Luogu3352 「ZJOI2016」线段树

先做一遍单调栈求出来 liri 表示最大值区间

然后题目转成在所有区间选择方法里面有多少是可以满足一个 lijriaj 被更新成了 ai

然后这里分成两个部分,第一个是直接区间覆盖的,另一个是间接区间覆盖的

就变成了一个数数题

段内要 dp

fp,i,j 表示已经把点 i 更新成 ap 同时进行了 j 次的方案数

然后转移推上半天也推不出来,自闭了一中午

转移考虑控制一段不可影响的区间然后剩下的快速幂乘上去,然后中间的部分 dp

发现内部之间是有影响的,自己并不会处理

重新定义状态:

fx,v,l,r 表示进行了 x 轮之后 lir,aiv 同时 al1,ar+1v+1 的方案

转移就比较好做:

fx,v,l,r=fx1,v,l,rgl,r+j<lfx1,v,j,r×(j1)+j>rfx1,v,l,j×(nj)

这里 gl,r 为瞎选区间与 [l,r] 无关的方案数

答案统计?(valj 为离散化后的结果)

ans=j=1nvalj×(sumi,jsumi,j1)

sumi,j=i[l,r]fj,m,l,r

直接做是 O(n4)

考虑优化:

这里每次转移的时候第一维都是固定的,所以我们把这维消掉:

dpi,l,r=j=1nfj,i,l,r

转移其实没变(这里感觉理解起来没啥问题,但是下次再遇到还真不知道能不能用上)

然后初始化的时候改动一下就好了

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
#define For(i,a,b) for(reg int i=a;i<=b;++i) 
#define Down(i,a,b) for(reg int i=a;i>=b;--i)
namespace yspm{
    inline int read()
    {
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k=='-') f=-1;
        while(isdigit(k)) res=res*10+k-'0',k=getchar();
        return res*f;
    }
    const int mod=1e9+7,N=410;
    int n,q,a[N],f[2][N][N],g[N][N],cur=1,ans[N],dp1[2][N][N],dp2[2][N][N];
    inline int max(int x,int y){return x>y?x:y;}
    inline int min(int x,int y){return x<y?x:y;}
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    inline int mul(int x,int y){return x*y-x*y/mod*mod;}
    inline int ksm(int x,int y)
    {
        int res=1; for(;y;y>>=1,x=mul(x,x)) if(y&1) res=mul(res,x);
        return res;
    }
    inline int calc(int x){return x*(x+1)/2%mod;}
    signed main()
    {
        n=read(); q=read(); For(i,1,n) a[i]=read();
        a[0]=2e18+10,a[n+1]=2e18+10;
        For(l,1,n) 
        {
            int mx=a[l];
            For(r,l,n)
            {
                mx=max(mx,a[r]);
                if(mx<min(a[l-1],a[r+1]))
                {
                    if(l==1&&r==n) f[cur][l][r]=mx;
                    else f[cur][l][r]=del(mx,min(a[l-1],a[r+1]));
                } g[l][r]=add(calc(l-1),add(calc(n-r),calc(r-l+1)));
            }
        }
        For(i,1,q) 
        {
            For(l,1,n)
            {
                For(r,l,n) dp1[cur][l][r]=add(mul(f[cur][l][r],l-1),dp1[cur][l-1][r]);  
                Down(r,n,l) dp2[cur][l][r]=add(mul(f[cur][l][r],n-r),dp2[cur][l][r+1]);
            } cur^=1;
            For(l,1,n) 
            {
                For(r,l,n) f[cur][l][r]=add(mul(f[cur^1][l][r],g[l][r]),add(dp1[cur^1][l-1][r],dp2[cur^1][l][r+1]));
            }
        }
        For(i,1,n) 
        {
            int sum=0;
            For(j,1,i) For(k,i,n) sum=add(sum,f[cur][j][k]);
            printf("%lld ",sum);
        } puts("");
        return 0;
    }
}
signed main(){return yspm::main();}
posted @   没学完四大礼包不改名  阅读(145)  评论(1编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示