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;
        }
    }
  • 相关阅读:
    在 Windows 上测试 Redis Cluster的集群填坑笔记
    vmware安装黑苹果教程
    微信支付v3发布到iis时的证书问题
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(安装篇SQL Server on linux)
    Linux下安装SQL Server 2016(准备篇SQL Server on linux)
    客服端与服务端APP支付宝支付接口联调的那些坑
    ASP.NET MVC]WebAPI应用支持HTTPS的经验总结
    .net平台下C#socket通信(中)
  • 原文地址:https://www.cnblogs.com/Saurus/p/6183721.html
Copyright © 2011-2022 走看看