Educational Codeforces Round 56 (Rated for Div. 2) F. Vasya and Array

题意:长度为n的数组,数组中的每个元素的取值在1-k的范围内或者是-1,-1代表这个元素要自己选择一个1-k的数字去填写,然后要求填完的数组中不能出现连续长度大于len的情况,询问填空的方案数。

题解:初始思想是设置一个dp[][],数组第一维代表当前连续长度,第二维代表选择的数字。那最终答案就是最后的dp数组元素之和。

   然后考虑更新这个数组:

     当前元素是-1的话,那么对于每个dp[1][x] (1<=x<=k),他就是上一次dp数组元素之和 - 上一次符合dp[i][x]的元素之和(也就是去掉自己,把别的都加上)。

   对于每个dp[i][x] (1<i<len, 1<=x<=k),他就是上一次对应的dp[i - 1][x]。①

   当前元素不是-1,那么对于当前元素对应的值x,更新方法是一样的。与此同时,把别的不等于当前元素的值的dp数组清空。

   接着考虑len的限制,那么len的限制其实就是要我们在更新dp的同时,去掉某个元素连续长度大于等于len的部分。②

   也就是说对于更新提出了两个要求,第一个就是可以快速滑动(①要求),第二个就是快速删除位于一端的数字(②要求),那么队列可以很好的满足要求。

#include<bits/stdc++.h>
using namespace std;
const int P = 998244353;
int a[100005], S[108], sum[108][2];
queue<int> q[108];
int main(){
    int n, k, len, Sum[2];
    scanf("%d%d%d", &n, &k, &len);
    for(int i = 1; i <= n; i++){
        scanf("%d", a + i);
    }
    if(k == 1){
        if(len <= n) return puts("0"),0;
        else return puts("1"),0; 
    }
    if(len == 1) return puts("0"),0;
    if(a[1] == -1){
        for(int i = 1; i <= k; i++) S[i] = sum[i][0] = 1, q[i].push(1);
        Sum[0] = k;
    }
    else S[a[1]] = sum[a[1]][0] = 1, q[a[1]].push(1), Sum[0] = 1;

    for(int i = 2; i <= n; i++){
        int ii = i & 1;
        Sum[ii ^ 1] = 0;
        if(a[i] == -1){
            for(int j = 1; j <= k; j++){
                q[j].push((Sum[ii] - sum[j][ii] + P) % P);
                sum[j][ii ^ 1] = Sum[ii];
                if(++S[j] == len) {
                    --S[j];
                    sum[j][ii ^ 1] = (sum[j][ii ^ 1] - q[j].front() + P) % P;
                    q[j].pop();
                }
                Sum[ii ^ 1] = (Sum[ii ^ 1] + sum[j][ii ^ 1]) % P;
            }
        }
        else{
            q[a[i]].push((Sum[ii] - sum[a[i]][ii] + P) % P);
            sum[a[i]][ii ^ 1] = Sum[ii];
            if(++S[a[i]] == len) {
                --S[a[i]];
                sum[a[i]][ii ^ 1] = (sum[a[i]][ii ^ 1] - q[a[i]].front() + P) % P;
                q[a[i]].pop();
            }
            for(int j = 1; j <= k; j++) if(j != a[i]){
                while(!q[j].empty()) q[j].pop();
                sum[j][ii ^ 1] = 0;
                S[j] = 0;
            }
            Sum[ii ^ 1] = sum[a[i]][ii ^ 1];
        }
    }
    printf("%d\n", Sum[((n + 1) & 1)]);
} 

 

posted @ 2018-12-18 11:54 Billyshuai 阅读(...) 评论(...) 编辑 收藏