CF1428 G1,G2 . Lucky Numbers题解

89 篇文章 1 订阅

CF1428 G1,G2 . Lucky Numbers

首先可以发现写下的这些数中最多只有一个数不是全部由0,3,6,9构成的。

然后其余的必须是3的倍数。可以发现这就是一个多重背包问题,将每一额物品拆分成 log ⁡ 2 \log_2 log2个就行了。

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=1000000;
int k;
int f[6];
int num=1;
LL dp[MAXN+20];
LL calc(int num){
	LL ret=0;
	rb(i,0,5){
		if((num%10)%3==0){
			ret+=1ll*(num%10)/3*f[i];
		}
		num/=10;
	}
	return ret;
}
int main(){
	scanf("%d",&k);
	k--;
	memset(dp,-127,sizeof(dp));
	dp[0]=0;
	rb(i,0,5){
		vector<pair<LL,LL> > obj; 
		scanf("%d",&f[i]);
		int cnt_obj=3*k;
		int z=1;
		while(cnt_obj>=z){
			cnt_obj-=z;	
			if(1ll*z*num<=1ll*MAXN)
			obj.PB(II(1ll*3*z*num,1ll*z*f[i]));
//			cout<<z*num<<' '<<z*f[i]<<endl;
			z<<=1;	
		}
		if(cnt_obj){
			if(1ll*cnt_obj*num<=1ll*MAXN)
			obj.PB(II(1ll*3*cnt_obj*num,1ll*cnt_obj*f[i]));
		}
		for(auto it:obj){
			rl(ii,MAXN,it.FIR){
				check_max(dp[ii],dp[ii-it.FIR]+it.SEC);
			}
		}
		rl(ii,MAXN,0)
			rb(j,0,9){
				if(j*num<=ii){
					check_max(dp[ii],dp[ii-j*num]+(j%3==0? 1ll*(j/3)*f[i]:0ll));
				}	
				else break;
			}
		num*=10;
	}
	int q;
	scanf("%d",&q);
	while(q--){
		int ni;
		scanf("%d",&ni);
		printf("%I64d\n",dp[ni]);
//		LL rest=0;
//		rb(i,0,ni){
//			if((ni-i)%3==0){
//				check_max(rest,dp[(ni-i)/3]+calc(i));
//			}
//		}
//		cout<<rest<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值