• 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
    ", Sum[((n + 1) & 1)]);
    } 
  • 相关阅读:
    linux less-分屏上下翻页浏览文件内容
    linux tail-在屏幕上显示指定文件的末尾若干行
    linux cut-连接文件并打印到标准输出设备上
    linux od-输出文件的八进制、十六进制等格式编码的字节
    linux hexdump-显示文件十六进制格式
    linux whereis-查找二进制程序、代码等相关文件路径
    linux find-在指定目录下查找文件
    linux which-查找并显示给定命令的绝对路径
    linux diff3-比较3个文件不同的地方
    Datetimepicker实现秒钟选择下拉框
  • 原文地址:https://www.cnblogs.com/mfys/p/10136255.html
Copyright © 2020-2023  润新知