• Codeforces Round #384 (Div. 2) E


    给出n个数字 1-8之间 要求选出来一个子序列 使里面1-8的数字个数 极差<=1 并且相同数字必须相邻(112 可以但是121不行)求这个子序列的最长长度 

    一道状压dp 看不懂别人的dp思想..自己造了一个出来..

    首先枚举t 意义是 当前选取子序列 每个数字最少是多少 那么这个子序列中的数字个数为t t+1

    dp[i][j]当前在i位 选取数字的情况压缩成j

    枚举没选过的数字 用前缀和进行二分查找

    从第i位开始 求出res使在满足i-res这个区间有t或者t+1的某数字 进行转移 更新dp[res][j|x] 

    当t为0的时候和t>0的时候 一个是 某种数字不选也可以 一个是每种数字都会被选择 所以分开来讨论

    前者就是统计出现过的数字的种数

    后者 当j|x为11111111 即每种数字都选完的时候 这时候才会满足 数字个数为t或者t+1 才可以进行对ans的更新

    时间复杂度 n^2 * (255) * log(n)

    一道题补了两天...期间打了好久游戏...QAQ

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<vector>
    #include<queue>
    #include<malloc.h>
    using namespace std;
    #define L long long
    int n ;
    int dp[1050][(1<<8) + 5];
    int a[1050];
    int b[(1<<8) + 5];
    int sum[1050][9];
    int main(){
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        int ans = 0;
        int mj = (1<<8) - 1;
        for(int i=0;i<=mj;i++){
            int z = i;
            b[z] = 0;
            while(z){
                if(z%2 == 1)b[i] ++;
                z/=2;
            }
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            for(int j=1;j<=8;j++)sum[i][j] = sum[i-1][j];
            sum[i][a[i]] ++ ;
        }
        for(int i=1;i<=8;i++){
            if(sum[n][i]>0)ans++;
        }
        for(int t=1;t*8<=n;t++){
            memset(dp , -1 ,sizeof(dp));
            dp[0][0] = 0;
            for(int i=0;i<n;i++){
                for(int j=0;j<=mj;j++){
                    if(dp[i][j] == -1)continue;
                    for(int k=1;k<=8;k++){
                        int z = (1<<(k-1));
                        if((z&j) == 0){
                            int g=(z|j);
                            int l = i+1;
                            int r = n;
                            int res = -1;
                            while(l<=r){
                                int mid =(l+r)/2;
                                if(sum[mid][k] - t > sum[i][k]){
                                    r = mid - 1;
                                }
                                else if(sum[mid][k] - t < sum[i][k]){
                                    l = mid + 1;
                                }
                                else {
                                    r = mid - 1;
                                    res = mid;
                                }
                            }
                            if(res != -1){
                                if(dp[res][g] == -1 || dp[res][g] < dp[i][j] + t){
                                    dp[res][g] = dp[i][j] + t;
                                    if(b[g] == 8)
                                        ans = max(dp[res][g] , ans);
                                }
                            }
                            l = i+1;
                            r = n;
                            res = -1;
                            while(l<=r){
                                int mid =(l+r)/2;
                                if(sum[mid][k] - t - 1> sum[i][k]){
                                    r = mid - 1;
                                }
                                else if(sum[mid][k] - t - 1< sum[i][k]){
                                    l = mid + 1;
                                }
                                else {
                                    r = mid - 1;
                                    res = mid;
                                }
                            }
                            if(res != -1){
                                if(dp[res][g] == -1 || dp[res][g] < dp[i][j] + t + 1){
                                    dp[res][g] = dp[i][j] + t + 1;
                                    if(b[g] == 8)
                                        ans = max(dp[res][g] , ans);
                                }
                            }
                        }
                    }
                }
            }
        }
        printf("%d
    ",ans);
    }
    

      

  • 相关阅读:
    实验一 命令解释程序的编写
    试验二
    实验一 命令解释程序的编写(重交)
    Sqlserver数据库帮助类(EFTools)
    js验证
    sqlserver中从日期字段取得月份
    IIS不可用或者有问题解决方法
    professional email address collections
    从psd文件到html
    空白符对HTML结构的影响与解决方案
  • 原文地址:https://www.cnblogs.com/rayrayrainrain/p/6186661.html
Copyright © 2020-2023  润新知