首页 > 其他分享 >洛谷 P4749 [CERC2017] Kitchen Knobs 题解

洛谷 P4749 [CERC2017] Kitchen Knobs 题解

时间:2023-10-19 09:58:35浏览次数:43  
标签:洛谷 组合 int 题解 合并 修改 P4749 Knobs Kitchen

Kitchen Knobs

首先,一个 trivial 的想法是,因为每个旋钮如果上面的数字并非全部相同则其必有唯一最优位置,故直接扔掉那些全部相同的旋钮,对于剩余的求出其最优位置。明显此位置是一 \(0\sim6\) 的数。

因为是区间同时旋转,所以转成数之后就是区间加同一个数。

一个经典套路是差分。这样就变成了每次同时修改序列中的两个数,一个加 \(x\),另一个减 \(x\)。当然,还可以只修改一个位置到任意值。

然后我们发现,对于一些和为 7 的倍数的数,我们只需要这些数的总数 \(-1\) 次“修改两个数”即可处理它们。

然后我们又发现,首先那些本身就是 0 的数可以直接扔掉,再怎么搞都不会修改到它们;这样的话,每次合并所能省下的次数最多只是 \(50\%\),因此我们一定会合并那些 \(50\%\) 的方案,即合并 \((1,6),(2,5),(3,4)\)。

这样合并完后,我们发现最多只剩下 3 种不同的数,因此一个 \(n^3\) 的 DP 就可以构思出来了。

然后我们还需要知道所有的和为 7 的组合。并且,这些组合必须是极小组合。于是我们直接 \(7^3\) 枚举三个数的次数,再 \(7^3\) 枚举其子集验证其是否是极小组合即可。

最后别忘记算 \((7,0,0),(0,7,0),(0,0,7)\) 这三种组合!!!因为没有考虑到这个我挂了很久。

这样一通算下来,极小组合数可以被视作很小的常数。于是直接 \(n^3\) 的 DP 即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int n,cmp,res,cnt;
int a[N],f[N][N][N],g[N][4],tot[8],lim[4],num[4];
string s,t;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s;
		t=s;
        bool as=true;
        for(int j=1;j<7;j++) if(s[j]!=s[0]){as=false;break;}
        if(as){
			i--;
			n--;
			continue;
		}
        for(int j=0;j<7;j++){
			rotate(s.begin(),s.begin()+1,s.end());
			t=max(t,s);
		}
        for(int j=0;j<7;j++){
            if(s==t){
				a[i]=j;
				break;
			}
            rotate(s.begin(),s.begin()+1,s.end());
        }
    }
    n++;
    for(int i=n;i>=2;i--) a[i]=(a[i]-a[i-1]+7)%7;
    for(int i=1;i<=n;i++) tot[a[i]]++;
    for(int i=1,x;i<=3;i++){
		x=min(tot[i],tot[7-i]);
		tot[i]-=x;
		tot[7-i]-=x;
		n-=x;
	}
    n-=tot[0];
    for(int i=1;i<7;i++){
		if(tot[i]){
			lim[cmp]=tot[i];
			num[cmp]=i;
			cmp++;
		}
	}
    for(int i=0;i<7;i++){
		for(int j=0;j<7;j++){
			for(int k=0;k<7;k++){
				if((i*num[0]+j*num[1]+k*num[2])%7) continue;
				if(!i&&!j&&!k) continue;
				bool ok=true;
				for(int I=0;I<=i;I++){
					for(int J=0;J<=j;J++){
						for(int K=0;K<=k;K++){
							if((I*num[0]+J*num[1]+K*num[2])%7) continue;
							if((!I&&!J&&!K)||(i==I&&j==J&&k==K)) continue;
							ok=false;break;
						}
					}
				}
				if(ok){
					g[cnt][0]=i;
					g[cnt][1]=j;
					g[cnt][2]=k;
					cnt++;
				}
			}
		}
	}
    g[cnt][0]=7;g[cnt][1]=0;g[cnt][2]=0;cnt++;
    g[cnt][0]=0;g[cnt][1]=7;g[cnt][2]=0;cnt++;
    g[cnt][0]=0;g[cnt][1]=0;g[cnt][2]=7;cnt++;
    for(int i=0;i<=lim[0];i++){
		for(int j=0;j<=lim[1];j++){
			for(int k=0;k<=lim[2];k++){
				for(int l=0;l<cnt;l++){
					if(i<g[l][0]||j<g[l][1]||k<g[l][2]) continue;
					f[i][j][k]=max(f[i][j][k],f[i-g[l][0]][j-g[l][1]][k-g[l][2]]+1);
				}
				res=max(res,f[i][j][k]);
			}
		}
	}
    cout<<n-res;
    return 0;
}

标签:洛谷,组合,int,题解,合并,修改,P4749,Knobs,Kitchen
From: https://www.cnblogs.com/xuantianhao/p/17773995.html

相关文章

  • [ABC207F] Tree Patrolling 题解
    [ABC207F]TreePatrolling弱智DP题,设\(f(i,j,0/1/2)\)表示在点\(i\),子树中有\(j\)个点被覆盖,且\(i\)点自身状态是未被覆盖/被自身覆盖/被某个儿子覆盖,然后树上背包更新就行了。代码:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintmo......
  • CF1542E2 Abnormal Permutation Pairs (hard version) 题解
    AbnormalPermutationPairs(hardversion)两个限制:字典序小、逆序对大,一个显然的想法就是确保一对关系,统计另一对关系。确保哪一对呢?我们想了想,决定确保字典序小,因为字典序是可以贪心的。具体而言,我们考虑两个排列自第\(i\)位开始出现了不同。这样子,我们便将两个排列各自划......
  • AT_tdpc_tree 木 题解
    木弱智DP题,直接设\(f_i\)表示\(i\)子树内染色的方案数,然后每次合并一个点与它的儿子即可(具体而言,因为儿子间独立,所以方案数就是二项式系数)。需要注意的是因为第一条边可以在任意位置,所以要以每个点为根各DP一次。但是这样每条边会被算两次,所以乘以2的逆元即可。时间......
  • [ARC072E] Alice in linear land 题解
    [ARC072E]Aliceinlinearland首先,一个trivial的想法是记\(f_i\)表示第\(i\)步前离终点的距离,于是\(f_i=\min\Big(f_{j-1},|f_{j-1}-d_i|\Big)\)。然后,我们设\(f_i'\)表示在修改第\(i\)步后,此时离终点的距离。明显,\(f_i'\)可以为任意不大于\(f_i\)的值,因为此时......
  • CF568E Longest Increasing Subsequence 题解
    LongestIncreasingSubsequenceLIS问题有两种主流\(O(n\logn)\)解法,最常见的树状数组法,以及不那么常见的二分法。然后考虑本题,发现一个神奇的思路就是求出LIS后倒序复原出数组。进一步思考后发现,因为本题是LIS(LongestIncreasingSubsequence)而非LNDS(LongestNon-Decr......
  • [AGC046D] Secret Passage 题解
    SecretPassage稍微观察一下就能发现,任一时刻,我们剩下的东西必然是一段定死了的后缀,加上一些可以任意塞位置的0与1。考虑任意一个由上述时刻生成的串,就会发现它与该后缀的最长公共子序列长度即为后缀长度,且还剩余一些0与1。于是考虑模拟最长公共子序列的过程。设\(g_{i,j......
  • Atcoder Beginner Contest 324 G Generate Arrays 题解-Treap
    为了更好的阅读体验,请点击这里题目链接套上平衡树板子就能做的很快的题,然后因为是指针存树,因此交换只需要把序列大小较小的挨个拿出来插到相应的地方即可。复杂度\(O(N\log^2N)\)。但是一定要记住不可以直接使用std::swap交换包含带有指针的类的实例(如代码中的Treap类)!......
  • 精选题解汇总
    Part1比赛题解CF1873CF1203CF1234CF1249Part2难题题解P1124P6346P2198P7974P4814......
  • P1124 题解
    题目大意一个长度为\(n\)的字符串\(S\),进行以下操作。假设\(s\)为acbdef,每一次将首字母移至末尾,得到\(6\)个字符串:acbdefcbdefabdefacdefacbefacbdfacbde将每个字符串的首字母排序:acbdefbdefaccbdefadefacbefacbdfacbde每个字符串的末尾连在一起为fcab......
  • Linux 环境下(Ubuntu)webbench的安装问题解决与使用
    webbench最多可以模拟3万个并发连接去测试网站的负载能力。并发能力比较高,可以测试https及动态静态页面。适合中小型网站测试承受能力。原理:父进程fork若干个子进程,每个子进程在用户要求时间或默认的时间内对目标web循环发出实际访问请求,父子进程通过管道进行通信,子进程通过......