gym102798 2020CCPC威海L Clock Master

4 篇文章 0 订阅
题目:

T T T组数据。
每组数据给定一个数 b b b,找出一组数 t t t,满足 ∑ i = 1 ∣ t ∣ t i ≤ b \displaystyle \sum_{i=1}^{|t|}t_i \le b i=1ttib v k = ( k % t 1 , k % t 2 , ⋯ k % t ∣ t ∣ ) v_k=(k\%t_1,k\%t_2,\cdots k\%t_{|t|}) vk=(k%t1,k%t2,k%tt)的种类数最多,其中 k k k为非负整数。
( 1 ≤ T , b ≤ 30000 ) (1 \le T,b \le 30000) (1T,b30000)

题解:

考虑什么情况下对于不同的 k k k v k v_k vk相同。设 k 1 , k 2 , k 1 ≠ k 2 k_1,k_2,k_1 \ne k_2 k1,k2,k1=k2
k 1 = a 1 t 1 + b 1 , k 1 = a 2 t 2 + b 2 , ⋯ k 1 = a ∣ t ∣ t ∣ t ∣ + b ∣ t ∣ k_1=a_1t_1+b_1,k_1=a_2t_2+b_2,\cdots k_1=a_{|t|}t_{|t|}+b_{|t|} k1=a1t1+b1,k1=a2t2+b2,k1=attt+bt
k 2 = c 1 t 1 + b 1 , k 2 = c 2 t 2 + b 2 , ⋯ k 2 = c ∣ t ∣ t ∣ t ∣ + b ∣ t ∣ k_2=c_1t_1+b_1,k_2=c_2t_2+b_2,\cdots k_2=c_{|t|}t_{|t|}+b_{|t|} k2=c1t1+b1,k2=c2t2+b2,k2=cttt+bt
那么显然 l c m ( t 1 , t 2 , ⋯   , t ∣ t ∣ ) ∣ ∣ k 2 − k 1 ∣ lcm(t_1,t_2,\cdots,t_{|t|})\mid|k2-k1| lcm(t1,t2,,tt)k2k1,所以不同的 v k v_k vk l c m ( t 1 , t 2 , ⋯   , t ∣ t ∣ ) lcm(t_1,t_2,\cdots,t_{|t|}) lcm(t1,t2,,tt)个。显然我们取的 t t t要两两互质,不然我们可以在达到原来的 l c m lcm lcm的同时使总和更小。那么考虑一个数 n = p 1 a 1 p 2 a 2 ⋯ p k a k n=p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k} n=p1a1p2a2pkak,有 p 1 a 1 p 2 a 2 ⋯ p k a k ≥ p 1 a 1 + p 2 a 2 + ⋯ + p k a k p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k}\ge p_1^{a_1}+p_2^{a_2}+\cdots +p_k^{a_k} p1a1p2a2pkakp1a1+p2a2++pkak,当且仅当 n = 4 = 2 × 2 n=4=2 \times 2 n=4=2×2时,等号成立,所以我们要找的 t t t一定是质数的幂次。打出质数的幂次可以发现就3000个左右,所以问题就变成了分组背包问题了,物品 a a a的体积为 a a a,价值为 ln ⁡ a \ln a lna,直接 d p dp dp即可。
注意由于 T T T很大,所以不要每次都求背包,要直接求30000的背包预处理出所有的答案。感觉有些卡常。

复杂度: O ( b 2 l o g b ) O(\frac{b^2}{logb}) O(logbb2)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;

#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=30005;
ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int T,b,tp;
int prim[maxn],vis[maxn];
double dp[maxn],ans[maxn],v[5005][20];
int a[5005][20];
void init(int n){
	tp=0;	
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prim[++tp]=i;
		}
		for(int j=1;i*prim[j]<=n;j++){
			vis[i*prim[j]]=1;
			if(i%prim[j]==0)break;
		}
	}
	for(int i=1;i<=tp;i++){
		for(int j=prim[i],k=1;j<=n;j*=prim[i],k++){
			a[i][k]=j;
			a[i][0]=k;
			v[i][k]=log(j);
		}
	}
	for(int i=0;i<=n;i++)dp[i]=-1e18;
	dp[0]=0;
	for(int i=1;i<=tp;i++){
		for(int j=n;j>=prim[i];j--){
			for(int k=1;k<=a[i][0];k++){
				if(a[i][k]>j)continue;
				if(dp[j-a[i][k]]>=0)dp[j]=max(dp[j],dp[j-a[i][k]]+v[i][k]);
			}
		}
	}
	ans[0]=dp[0];
	for(int i=1;i<=n;i++)ans[i]=max(ans[i-1],dp[i]);
}
int main(void){
	// freopen("in.txt","r",stdin);
	init(30000);
	scanf("%d",&T);
	while(T--){
		scanf("%d",&b);
		printf("%.9f\n",ans[b]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值