[DP]Codeforces 743E Vladik and cards

本文介绍了一种算法,用于解决寻找符合条件的最长子序列的问题。该子序列中任意两个数字出现次数之差不超过1,并且相同元素在原始序列中是连续的。文章通过动态规划方法实现,并详细阐述了具体的实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目梗概

给出 n 个元素的序列,每个元素的是大小不超过 8 的正整数。请找出满足下面两个条件的最长
子序列:
1. 任意两个数字出现的次数之差的绝对值不超过 1, 未出现的算 0次;
2. 相同的元素是连续的(在原始序列中可以不连续)。

解题思路

首先枚举一个t表示每个数的个数为t或t+1(这里其实可以二分)。

因为每个数选择的区间必须连续,所以可以用DP验证。

f[i][j]表示前i个数,j状态下的最大长度(j表示每个是否取过)。
转移方程显然。

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1005,m=256;
int sum[maxn][10],n,f[maxn][300];
int max(int x,int y){if (x>y) return x;return y;}
int find(int x,int y,int L){
    int R=n,mid;
    if (sum[L][y]>=x) return L;
    while(L<=R){
        mid=L+(R-L>>1);
        if (sum[mid-1][y]<x&&x<=sum[mid][y]) return mid;
        if (x>sum[mid][y]) L=mid+1;else R=mid-1;
    }
    return -1;
}
int work(int t){
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for (int i=0;i<=n;i++)
    for (int j=0;j<m;j++) if (f[i][j])
    for (int k=0;k<8;k++) if (((1<<k)&j)==0){
        int x1=find(sum[i][k+1]+t,k+1,i),x2=find(sum[i][k+1]+t+1,k+1,i);
        if (x1!=-1) f[x1][j+(1<<k)]=max(f[x1][j+(1<<k)],f[i][j]+t);
        if (x2!=-1) f[x2][j+(1<<k)]=max(f[x2][j+(1<<k)],f[i][j]+t+1);
    }
    int ans=0;
    for (int i=1;i<=n;i++) ans=max(ans,f[i][m-1]);
    return ans-1;
}
int main(){
    freopen("longseq.in","r",stdin);
    freopen("longseq.out","w",stdout);
    scanf("%d",&n);
    for (int i=1,x;i<=n;i++){
        scanf("%d",&x);
        for (int j=1;j<=8;j++) sum[i][j]=sum[i-1][j]+(j==x);
    }
    for (int i=n/8;i>=0;i--){
        int x=work(i);
        if (x!=-1) return printf("%d",x),0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值