2020-11-02 NOIP模拟T1

题解

使用操作 1 1 1只是为了给操作 2 2 2或操作 3 3 3凑整,因此问题变为递归考虑在进行了 x 1 x1 x1次操作 1 1 1后再进行 x 2 x2 x2次操作 2 2 2或者操作 3 3 3使得 ( x 1 + x 2 ) (x1+x2) (x1+x2)有最小值即可。
于是按照这个思路对问题进行分治处理,设 f n f_n fn为将 n n n操作到 0 0 0所需要的最小次数,可以得到如下式子:
f n = m i n { f n , f ( n / 2 ) + ( n % 2 ) , f ( n / 3 ) + ( n % 3 ) } f_n=min\{f_n,f_{(n/2)}+(n\%2),f_{(n/3)}+(n\%3)\} fn=min{fn,f(n/2)+(n%2),f(n/3)+(n%3)}
其中取模操作就相当于操作 1 1 1 / 2 /2 /2 / 3 /3 /3就相当于进行操作 1 1 1后的操作 2 2 2或操作 3 3 3,然后一起取个最小值即可。可以使用 S T L STL STL m a p map map进行记忆化。
初始化 f 1 = 1 , f 0 = 0 f_1=1,f_0=0 f1=1,f0=0
注意当 n = = 2 n==2 n==2 n = = 3 n==3 n==3时,次数为 2 2 2,但是代入上式因为 % 2 o r % 3 = = 0 \%2 or\%3==0 %2or%3==0,所以我们需要在判断时加一句 ( n ≥ 2 ) (n\ge2) (n2) ( n ≥ 3 ) (n\ge 3) (n3)处理一下即可。

考场

当时看到 n ≤ 1 e 9 n\le 1e9 n1e9的范围时想到了对其要分治递归处理,但是因为题做的不够所以直接考虑的用自己瞎想还想错了的最优搜索顺序进行搜索后得答案而没有分开搜索取 m i n min min。考场上想的是先搜 3 3 3比先搜 2 2 2更优而没有考虑这样搜索之后后面的值不一定更优,所以要多手玩数据找规律,发现操作 1 1 1其实就相当于取模为操作 2 , 3 2,3 23做准备后再联想到对每条搜索路径分治 + + +记忆化之后思路就很显然了。
其实这道题正解和暴力思路很像,只不过暴力是用 d p dp dp预处理 n ≤ 1 e 7 n\le 1e7 n1e7,相当于复杂度就是 O ( n ) O(n) O(n),而考虑缩小暴力复杂度就是对 n n n进行操作,实际式子和暴力其实没什么区别。

总结

考场上一定要先想暴力,因为暴力会给正解一定的思路,就像这道题的式子是一样的,再考虑暴力复杂度主要是哪里过不去,那么就在正解里对这个复杂度进行处理,就像这道题对 n n n进行分治,那么正解也就呼之欲出了。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1000050;
const int M=35;
int T,n,f[N];
int ans=1;
map<int,int> mp;
int dp(int n){
	if(n==0) return 0;
	if(n==1) return 1;
	if(mp.count(n)) return mp[n];
	int ans1=dp(n/2)+n%2+(n>=2);
	int ans2=dp(n/3)+n%3+(n>=3);
	mp[n]=min(ans1,ans2);
	return mp[n];
}
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<1)+(cnt<<3)+(c^48);c=getchar();}
	return cnt*f;
}
signed main(){
	freopen("magic.in","r",stdin);
	freopen("magic.out","w",stdout);
	ios::sync_with_stdio(false);
	cout.tie(0);
	T=read();
	while(T--){
		n=read();
		cout<<dp(n)<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值