Processing math: 100%

Luogu P4933 大师(dp)

P4933 大师

题意

题目背景

建筑大师最近在跟着数学大师ljt12138学数学,今天他学了等差数列,ljt12138决定给他留一道练习题。

题目描述

ljt12138首先建了n个特斯拉电磁塔,这些电塔排成一排,从左到右依次标号为1n,第i个电塔的高度为h[i]

建筑大师需要从中选出一些电塔,然后这些电塔就会缩到地下去。这时候,如果留在地上的电塔的高度,从左向右构成了一个等差数列,那么这个选择方案就会被认为是美观的。

建筑大师需要求出,一共有多少种美观的选择方案,答案模998244353

注意,如果地上只留了一个或者两个电塔,那么这种方案也是美观的。地上没有电塔的方案被认为是不美观的。

输入输出格式

输入格式:

第一行一个正整数n

第二行n个非负整数,第i个整数是第i个电塔的高度h[i]

输出格式:

输出一个整数,表示美观的方案数模998244353的值。

输入输出样例

输入样例#1:

8
13 14 6 20 27 34 34 41

输出样例#1:

50

输入样例#2:

100
90 1004 171 99 1835 108 81 117 141 126 135 144 81 153 193 81 962 162 1493 171 1780 864 297 180 532 1781 189 1059 198 333 1593 824 207 1877 216 270 225 1131 336 1875 362 234 81 288 1550 243 463 1755 252 406 261 270 279 288 1393 261 1263 297 135 333 872 234 881 180 198 81 225 306 180 90 315 81 81 198 252 81 297 1336 1140 1238 81 198 297 661 81 1372 469 1132 81 126 324 333 342 81 351 481 279 1770 1225 549

输出样例#2:

11153

说明

我们用v表示最高的电塔高度。

对于前30%的数据,n20

对于前60%的数据,n100,v2000

对于另外20%的数据,所有电塔的高度构成一个等差数列。

对于100%的数据,n1000,v20000

思路

这而应该是个O(nv)的题,然而被我小常数O(n3)水过了。

设计状态f[i][j]表示当前等差数列的最后两项分别为i,j的方案数,特别的,如果数字j作为等差数列的开头,记作f[0][j]。之所以这样记录,是因为我们只需要知道等差数列的最后两项就可以得到等差数列的公差,而等差数列的转移由于前面的项无关,所以这样不会丢失信息。

转移也很简单,不过要判断能否转移。

for(LL i=1;i<=n;i++) f[0][i]=1;
for(LL i=2;i<=n;i++)
    for(LL j=1;j<i;j++)
    {
        f[j][i]=f[0][j];
        for(LL k=1;k<j;k++) if(a[i]-a[j]==a[j]-a[k]) f[j][i]=(f[j][i]+f[k][j])%P;
        ans=(ans+f[j][i])%P;
    }

想到的一个优化方法是直接记录公差减少判断次数,不过既然水过了那就不改了(逃

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL P=998244353;
LL n,ans,a[1005],f[1005][1005];
LL read()
{
    LL re=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
    return re;
}
int main()
{
    ans=n=read();
    for(LL i=1;i<=n;i++) a[i]=read(),f[0][i]=1;
    for(LL i=2;i<=n;i++)
        for(LL j=1;j<i;j++)
        {
            f[j][i]=f[0][j];
            for(LL k=1;k<j;k++) if(a[i]-a[j]==a[j]-a[k]) f[j][i]=(f[j][i]+f[k][j])%P;
            ans=(ans+f[j][i])%P;
        }
    printf("%lld",ans);
    return 0;
}
posted @   UranusITS  阅读(202)  评论(0编辑  收藏  举报
编辑推荐:
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
阅读排行:
· 2025成都.NET开发者Connect圆满结束
· 后端思维之高并发处理方案
· 千万级大表的优化技巧
· 在 VS Code 中,一键安装 MCP Server!
· 10年+ .NET Coder 心语 ── 继承的思维:从思维模式到架构设计的深度解析
点击右上角即可分享
微信分享提示