10.12 代码源 2024 CSP-S 模拟赛 Day 14

省流:\(100+0+0+8=108\)

简称:唐诗

T1

首先发现 \(a\) 序列一定先降后升,然后 \(n\le 100\)

然后很容易想到一个朴素 DP

离散之后,\(f[mxl][sel][mxr][ser]\) 表示单减最大和次大,单增最大和次大

然后做一个 \(O(n^4)\) 的 DP 即可

O(n^4) DP
f[1][0][1][0]=C;
fd(mxl,1,n)//max l
{
    fd(sel,0,mxl-1)//second max l
    {
        fd(mxr,1,n)//max r
        {
            fd(ser,0,mxr-1)//second max r
            {
                int mx=max(mxl,mxr);
                if(mx==n) {(ans+=f[mxl][sel][mxr][ser])%=mod;continue;}
                if(a[mx+1]-a[mxl]>=a[mxl]-a[sel]||sel==0)
                    (f[mx+1][mxl][mxr][ser]+=f[mxl][sel][mxr][ser])%=mod;
                if(a[mx+1]-a[mxr]>=a[mxr]-a[ser]||ser==0)
                    (f[mxl][sel][mx+1][mxr]+=f[mxl][sel][mxr][ser])%=mod;
            }
        }
    }
}

其实这个就能过了,因为空间限制是 \(1024MB\)\(f\) 数组开到 \(10^8\) 没问题,但是我开的 un_map 有大常数,然后就过不去最后一个大样例……

然后考虑优化,发现很多时候转移不了,所以合法状态不多,用优先队列存下合法的位置即可

复杂度最劣 \(O(n^4 \log n^4)\),但是跑不满,甚至还是最优解……

注意,一个点最多更新别人一次,所以要开一个 \(v\) 数组记一下,否则可能会重复贡献

优先队列优化
struct node{int mxl,sel,mxr,ser;};
inline bool operator<(node x,node y)
{
    if(x.mxl!=y.mxl) return x.mxl>y.mxl;
    if(x.sel!=y.sel) return x.sel>y.sel;
    if(x.mxr!=y.mxr) return x.mxr>y.mxr;
    return x.ser>y.ser;
}
//-----------------------------------------------------------
f[1][0][1][0]=C;
q.push({1,0,1,0});
while(!q.empty())
{
    node now=q.top();q.pop();
    int mxl=now.mxl,mxr=now.mxr,sel=now.sel,ser=now.ser;
    if(v[mxl][sel][mxr][ser]) continue;
    v[mxl][sel][mxr][ser]=1;
    int mx=max(mxl,mxr);
    if(mx==n) {(ans+=f[mxl][sel][mxr][ser])%=mod;continue;}
    if(a[mx+1]-a[mxl]>=a[mxl]-a[sel]||sel==0)
    {
        (f[mx+1][mxl][mxr][ser]+=f[mxl][sel][mxr][ser])%=mod;
        if(v[mx+1][mxl][mxr][ser]) continue;
        q.push({mx+1,mxl,mxr,ser});
    }
    if(a[mx+1]-a[mxr]>=a[mxr]-a[ser]||ser==0)
    {
        (f[mxl][sel][mx+1][mxr]+=f[mxl][sel][mxr][ser])%=mod;
        if(v[mxl][sel][mx+1][mxr]) continue;
        q.push({mxl,sel,mx+1,mxr});
    }
}

赛时很多人有记忆化冲过去了……

T2

开始写了一个暴力,赛后发现最小的点都 T 了……

然后推了大概十来分钟柿子,然后码了个组合数发现样例过不去

然后发现没注意到 \(0≤b_1<b_2<...<b_n≤m\) ……

赛后发现不算难,是个数位 DP

AC Code
int n,m,a[N],ans;
struct node
{
    int mx,cnt;
	node (int x=-1e18,int y=0) {mx=x,cnt=y;}
    node operator+(node y) {return node(mx+y.mx,cnt*y.cnt%mod);}
    node operator+(int y) {return node(mx+y,cnt%mod);}
    node operator-(int y) {return node(mx-y,cnt%mod);}
	inline void print() {cout<<mx<<' '<<cnt%mod<<endl;}
}f[M][N][N][2];

inline node Max(node x,node y)
{
    if(x.mx<y.mx) return y;
    if(x.mx>y.mx) return x;
    return node(x.mx,(x.cnt+y.cnt)%mod);
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin>>n>>m;
    fd(i,1,n)
    {
        cin>>a[i];a[i]+=a[i-1];
        f[0][i][i][0]=f[0][i][i][1]=(node){0,1};
    }
    fd(i,0,60) fd(j,1,n+1)
        f[i][j][j-1][0]=f[i][j][j-1][1]=(node){0,1};
    fd(i,1,60)
	{
		fd(l,1,n)
	    {
			fd(r,l,n)
	        {
				if(m&(1ll<<(i-1))) fd(k,l-1,r) f[i][l][r][1]=Max(f[i][l][r][1],f[i-1][l][k][0]+f[i-1][k+1][r][1]+a[r]-a[k]);
				else f[i][l][r][1]=f[i-1][l][r][1];
				fd(k,l-1,r) f[i][l][r][0]=Max(f[i][l][r][0],f[i-1][l][k][0]+f[i-1][k+1][r][0]+a[r]-a[k]);
	        }
	    }
    }
	f[60][1][n][1].print();
    return 0;
}

T3

题都没咋看……

T4

很有思路

然后码了个暴力,又加了几个剪枝

但是子任务 \(2\) 也没跑过去……

总结

  • DP 还是得练

  • 暴力一定要拿满,最好优化一下,说不定就像 T1 一样加个记忆化就 A 了

\(\LARGE{唐}\)

举办匚5尺杪沃丅丨

posted @   whrwlx  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示