zoukankan      html  css  js  c++  java
  • 新春消消乐 题解

    给大家提前拜个早年!

    第一档

    测试贪心强不强的一档分,如果贪心策略很好的话,能拿到这一档的全部分数。

    附上zyz的贪心代码 ((40pts)):

    #include<bits/stdc++.h>
    using namespace std;
    string str;
    map<string,int>Ans;
    int calc(string s)
    {
    	// cout<<s<<'
    ';
    	if(Ans[s])return Ans[s];
    	int tot[10],maxx=9,temp=0,last=-1;
    	memset(tot,0,sizeof tot);
    	for(int i=0;i<s.size();i++)
    	tot[s[i]-'0']++;
    	for(int i=0;i<10;i++)
    	if(tot[i]>=tot[maxx])maxx=i;
    	int nowmax;
    	for(int num=0;num<10;num++){
    		// if(tot[num]!=tot[maxx])continue;
    		if(tot[num]==0)continue;
    		nowmax=tot[num]*tot[num];
    		last=-1;
    		for(int i=0;i<s.size();i++)
    		if(s[i]-'0'==num){
    			if(last+1<i-1)nowmax+=calc(s.substr(last+1,i-last-1));
    			if(last+1==i-1)nowmax++;
    			last=i;
    		}
    		if(last+1<s.size()-1)nowmax+=calc(s.substr(last+1,s.size()-last-1));
    		if(last+1==s.size()-1)nowmax++;
    		temp=max(temp,nowmax);
    	}
    	Ans[s]=temp;
    	return temp;
    }
    int main()
    {
    	int T,ans=0;
    	cin>>T;
    	while(T --> 0){
    		cin>>str;
    		ans+=calc(str);
    	}
    	cout<<ans<<'
    ';
    }
    

    不过这一档也可以通过暴力枚举删数次序,来算出答案。

    第二档

    将连续相同的数放在一个块里。

    建一个结构体,存放连续相同的数的值和长度。

    把字符串变成块后,只会出现01交替的情况,从两边开始删一定不优,从中间开始删,块两边一定能合并。

    因此,每删掉一个块,这个块两边的块会合成一个,相当于一次去掉了两个块,而性质满足块的数量 (le20) ,这样就可以愉快的搜索了。

    第三档

    留给写正解数组开小或者常数极大的选手。

    满分题解

    思考方法

    看到题目后,单纯贪心策略有问题,考虑DP。

    发现数据范围很小,要求出的是删除一段数字的最大值,可以用区间DP处理。

    设置状态

    (f_{l,r}) 表示 删除区间 ([l,r]) 的最大收益?

    删除 ([l,r]) 可能会在边界还会有连续的数字,删除区间后还会有左右两边的合并问题,存在后效性。

    本着写不出来多加一维的原则

    (f_{l,r,siz}) 表示 删除区间 ([l,r]) 且区间后连着长度为 (siz) 与右端点相同数字的串,的最大收益。

    目标状态为: (f_{1,len,0})

    状态转移

    (f_{l,r,siz}) 的状态转移有两种状况

    • 删去最右端的连续块。

    • 在区间内找到代表的数字与最右端相同的一个块,将这两块之间删去,使得区间最右端连着的那部分变长。

    枚举转移有点麻烦,可以通过记忆化搜索来解决。

    递归边界为 (l=r)

    Code
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 235
    #define LL long long 
    using namespace std;
    
    char S[N];
    int idx,last_num,ans;
    int T,len,f[N][N][110];//f如题解所述
    struct block
    {
        int len,num;//len存块的长度,num存块所代表的的数字
    }blo[N];
    
    inline int qr()//平平无奇的快读
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    
    int dfs(int l,int r,int siz)//记忆化搜索求解
    {
        if(f[l][r][siz])//搜过了就不搜了,直接返回答案
            return f[l][r][siz];
        if(l==r)//递归边界
            return f[l][r][siz]=(blo[r].len+siz)*(blo[r].len+siz);//贡献为块本身长度加上右端连着的长度
        f[l][r][siz]=dfs(l,r-1,0)+(blo[r].len+siz)*(blo[r].len+siz);//直接把右端和右端连着的一起删掉
        for(register int k=l;k<r;k++)
            if(blo[k].num==blo[r].num)//找到与右端数字相同的块
                f[l][r][siz]=max(f[l][r][siz],dfs(l,k,blo[r].len+siz)+dfs(k+1,r-1,0));//收益为这一块与右端拼起来的收益 加上 删除这一块与右端之间的块的收益
        return f[l][r][siz];//返回答案
    }
    
    int main()
    {
        //freopen("game.in","r",stdin);
        //freopen("game.out","w",stdout);
        T=qr();
        while(T--)
        {
            scanf("%s",S+1);
            len=strlen(S+1);
            memset(f,0,sizeof(f));
            last_num=-1;//最后一个块代表的数字
            idx=0;//块的数量
            for(register int i=1;i<=len;i++)//分成块
                if(((S[i]^48))!=last_num)//如果这个数字与上一个块不相等
                {
                    blo[++idx]=(block){1,(S[i]^48)};//新加一个块长度为1
                    last_num=(S[i]^48);//更新
                }
                else
                    blo[idx].len++;//如果数字相等块长+1
            ans+=dfs(1,idx,0);//累加答案
        }
        printf("%d
    ",ans);
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    C#学习笔记——读写ini文件
    C#学习笔记——控件
    C#学习笔记——SerialPort类
    halcon学习笔记——遍历文件夹与文件选择
    halcon学习笔记——图像的预处理
    C#中创建和使用动态链接库
    C#学习笔记——控件的命名规范
    halcon学习笔记——(1)HDevelop language(语法结构特点)
    C#学习笔记——基础概念回顾
    C#学习笔记——继承窗体
  • 原文地址:https://www.cnblogs.com/isonder/p/14384340.html
Copyright © 2011-2022 走看看