zoukankan      html  css  js  c++  java
  • Codeforces Round #384 (Div. 2) 734E(二分答案+状态压缩DP)

    题目大意

    给定一个序列an,序列中只有1~8的8个整数,让你选出一个子序列,满足下列两个要求

    1.不同整数出现的次数相差小于等于1

    2.子序列中整数分布是连续的,即子序列的整数必须是1,1,1....1,2,2,2.....2,2.......连续分布

    做法:

    那么我们可以二分不同整数出现的次数,假如说二分出现次数是L,那么可以证明有a个整数出现次数是L,有(8-a)个整数出现次数是L-1(同时不难证明L+1比L更优)

    这样每个整数只有两种状态,要么选L个,要么选L-1个。

    压缩决策s,s的第i位表示是否对整数i做出了决策

    再用容器把每一个不同整数出现的序列记录下来,这样就可以进行dp了

    设dp[i][s]表示从原序列扫到前i个数,已经做出了s的决策,出现L次的不同整数个数最大是多少

    枚举对第k个整数做决策,dp[i][s]就可以转移到另外两个状态

    dp[next(k, L-1)][s|(1<<k)] = max(itself, dp[i][s]);

    dp[next(k, L)][s|(1<<k)] = max(itself, dp[i][s]+1);

    其中next(k, L)是指从i开始,往后的第L个k的整数位置

    然后取dp[1~n][(1<<8)-1]中的最大值,返回答案即可

    另外如果最大值小于等于0(注意等于!!),说明不存在解,返回0即可。

    需要注意的是,当l = 2都不可行的时候需要特判处理。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn = 1111;
    const int inf = 1e9;
    int dp[maxn][1<<8], a[maxn], cur[maxn], n;
    vector <int> in[10];
    int can(int L)
    {
        for(int i = 1; i <= 8; i++) cur[i] = 0;
        memset(dp, 128, sizeof(dp));
        dp[1][0] = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int s = 0; s < (1<<8); s++)
            {
                if(dp[i][s] < 0) continue;
                for(int k = 1; k <= 8; k++)
                {
                    if(s & (1<<(k-1))) continue;
                    if(in[k].size() - cur[k] < L-1) continue;
                    dp[in[k][cur[k] + L - 2]][s|(1<<(k-1))] = max(dp[in[k][cur[k] + L - 2]][s|(1<<(k-1))], dp[i][s]);
                    if(in[k].size() - cur[k] < L)  continue;
                    dp[in[k][cur[k] + L - 1]][s|(1<<(k-1))] = max(dp[in[k][cur[k] + L - 1]][s|(1<<(k-1))], dp[i][s]+1);
                }
            }
            cur[a[i]]++;
        }
        int ans = -inf;
        for(int i = 1; i <= n ; i++) ans = max(ans, dp[i][(1<<8) - 1]);
        if(ans <= 0) return 0;
        return ans * L + (8 - ans)*(L-1);
    }
    
    int main()
    {
        //freopen("a.txt", "r", stdin);
        cin>>n;
        for(int i = 1; i <= n; i++) cin>>a[i];
        for(int i = 1; i <= n; i++) in[a[i]].push_back(i);
        int l = 2, r = n, ans = -inf;
        while(l < r)
        {
            int mid = (l+r)>>1;
            if(can(mid)) l = mid+1;
            else r = mid;
        }
        if(can(2) == 0)
        {
            ans = 0;
            for(int i = 1; i <= 8; i++) if(in[i].size() > 0) ans++;
            cout<<ans<<endl;
        }
        else
        {
            ans = max(can(l), can(l-1));
            cout<<ans<<endl;
        }
    }
  • 相关阅读:
    SBT树
    WGS84、Web墨卡托、火星坐标、百度坐标互转
    Chord算法
    马尔科夫及隐含马尔科夫模型
    VirtualBox的四种网络连接方式
    匈牙利算法求解任务分配问题
    回溯与分支定界
    【Docker】docker安装mysql
    【RocketMQ】同一个项目中,同一个topic,可以存在多个消费者么?
    【Feign调用异常】org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
  • 原文地址:https://www.cnblogs.com/Saurus/p/6183721.html
Copyright © 2011-2022 走看看