• How many groups(DP)


    题意:
    定义:设M为数组a的子集(元素可以重复),将M中的元素排序,若排序后的相邻两元素相差不超过2,则M为a中的一个块,块的大小为块中的元素个数

    给出长度为n的数组a,1<=n<=200,1<=ai<=200,可以任选最多两个数(可以不选),将它们值+1或-1。问如何修改可以使得数组中最大的块的大小最大。

    思路

    想到是否可以DP:第一维是数组中的下标;由于最多能修改两次,要有一维记录当前状态的修改次数;为了能递推,还要一维记录当前状态的修改值是+1还是-1。

    因此定义(dp[i][j][k]):对于排序后的数组,前i个数总共修改了j次,将第i个数修改位a[i]+k-1(如果没有修改,k=1),前i数最大块的大小。

    P.S. T=1e5,n*T=1e7,需要快读

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    int a[maxn];
    int dp[maxn][3][3];//dp[i][j][k]:到第i个数为止总共修改了j次,将a[i]+k-1后,前i个数的最大集合大小
    inline int read() {
    	int ret = 0, f = 1;
    	char ch = getchar();
    	while (ch<'0' || ch > '9') {
    		if (ch == '-')
    			f = -f;
    		ch = getchar();
    	}
    	while (ch >= '0'&&ch <= '9') {
    		ret = ret * 10 + ch - '0';
    		ch = getchar();
    	}
    	return ret *= f;
    }
    int main(){
        int t,n;
        t=read();
        for(int kase=1;kase<=t;kase++){
            n=read();
            for(int i=1;i<=n;i++)
                a[i]=read();
            sort(a+1,a+1+n);
            memset(dp,0,sizeof(dp));
            int ans=1;
            dp[1][0][1]=dp[1][1][0]=dp[1][1][2]=1;
            for(int i=2;i<=n;i++){
                for(int j=0;j<=2;j++){//到i改动了j次
                    if(j==0){//到a[i]一次未改
                        if(a[i]-a[i-1]<=2)
                            dp[i][0][1]=dp[i-1][0][1]+1;
                        else dp[i][0][1]=1;
                        continue;
                    }
                    for(int k=0;k<=2;k++){//a[i]
                        dp[i][j][k]=1;//初始化为1
                        for(int l=0;l<=2;l++){//a[i-1]
                            int ai=a[i]+k-1,aj=a[i-1]+l-1;
                            if(k==1){//a[i]不修改
                                if(ai-aj<=2)
                                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][l]+1);
                            }
                            else{
                                if(ai-aj<=2)
                                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][l]+1);
                            }
                        }
                    }
                }
                for(int j=0;j<=2;j++)
                    for(int k=0;k<=2;k++)
                        ans=max(ans,dp[i][j][k]);
            }
            printf("Case %d: %d
    ",kase,ans);
        }
    }
    
  • 相关阅读:
    hibernate和ibatis的区别
    [转] hibernate和ibatis的对比
    如何理解java的引用传递
    代理模式与装饰器模式的区别
    j2ee的异步消息机制
    什么是j2ee ??EJB与j2ee的关系?? 请看百度百科
    spring事务的传播性的理解
    Hibernate与IBatis的优缺点及可行性分析
    jQuery插件实现的方法和原理简单说明
    iReport使用教程
  • 原文地址:https://www.cnblogs.com/ucprer/p/11633763.html
Copyright © 2020-2023  润新知