CF 1093 F Vasya and Array

14 篇文章 0 订阅

题意:

给出一段长度为 n 的整数序列,一个正整数 k ,一个正整数 len ,序列中的所有数均在 1 ~k 之间,或者等于 −1

如果没有长度大于 len 的连续相同数字则该数段是好的。

可以将 -1 改为 1 ~k 之间的整数,将该数列变为好的,求出方案数,对 998244353 取模

 

思路:

F[i][j]表示第i个位置填数字j的方案数。

S[i]表示填完前i个位置的方案数

如果第i为j或者-1,则第i位可以为j :F[i][j]=s[i-1]

但是会有重复的情况:#@¥@#¥@XXXX(len个X)

怎么把这种情况删除,首先一点len区间的数要么就是X或者-1才会出现上面的情况。

重复的个数是s[i-len]-f[i-len][j],在i-len的位置上除了填j外另外的所有可以结尾的数字都可以加上一段X得到状态f[i][j]

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define ll long long
#define maxn 4001000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int P=998244353;
int n,k,len,cnt[101000][110],f[101000][110],s[101000],a[101000];
ll rd()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init()
{
    n=rd();k=rd();len=rd();
    rep(i,1,n) a[i]=rd();
    s[0]=1;
    rep(i,1,k)
        rep(j,1,n)
            cnt[j][i]=cnt[j-1][i]+(a[j]==i||a[j]==-1?1:0);
}
void work()
{
    memset(f,0,sizeof(f));
    rep(i,1,n)
    {
        rep(j,1,k)
        {
            if(a[i]!=-1&&a[i]!=j) continue;
            f[i][j]=s[i-1];
            if(i>=len&&cnt[i][j]-cnt[i-len][j]==len)
            {
                f[i][j]=(f[i][j]-s[i-len]+f[i-len][j])%P;
                f[i][j]=(f[i][j]+P)%P;
            }
        }
        rep(j,1,k)
            s[i]=(s[i]+f[i][j])%P;
    }
    printf("%d\n",s[n]);
}
int main()
{
    init();
    work();
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值