题目描述
Rishi is developing games in the 2D metaverse and wants to offer game bundles to his customers. Each game has an associated enjoyment value. A game bundle consists of a subset of games whose total enjoyment value adds up to $ 60 $ .
Your task is to choose $ k $ games, where $ 1 \leq k \leq 60 $ , along with their respective enjoyment values $ a_1, a_2, \dots, a_k $ , in such a way that exactly $ m $ distinct game bundles can be formed.
输入格式
The input is a single integer $ m $ ( $ 1 \le m \le 10^{10} $ ) — the desired number of game bundles.
输出格式
The first line should contain an integer $ k $ ( $ 1 \le k \le 60 $ ) — the number of games.
The second line should contain $ k $ integers, $ a_1, a_2, \dots, a_k $ ( $ 1 \le a_1, a_2, \dots, a_k \le 60 $ ) — the enjoyment values of the $ k $ games.
首先对于一个选择的集合,大于 30 的数最多只会选择一次。
所以考虑随机一个只由小于等于 30 的数组成的数列,然后在后面增加大于 30 的数。
首先想到到不断在后面增加小于等于 30 的数。每增加一个就是一下可不可以跑出来答案。
怎么试呢?定义 \(dp_i\) 为组成 \(i\) 的方案数,那么增加某一个大于 30 的数 \(x\) 增加的方案数是 \(dp_{60-x}\)。把所有的 dp 值从大到小排序后,能选就选。
然后发现这种方式凑出来的 \(m\) 不能超过 \(10^8\),但是正确率很高。
考虑为什么凑出来方案数太少,这是因为小于 30 的数重复的太少。
枚举一个 \(lim\),然后新增的时候强制序列中的数不超过 \(lim\),就能过了。
#include<bits/stdc++.h>
using namespace std;
int a[65],id[65];
long long n,m,dp[65];
int T,fl;
mt19937 gen(time(0));
int cmp(int x,int y)
{
return dp[x]>dp[y];
}
int main()
{
scanf("%lld",&n);
while(1)
{
for(int j=30;j;j--)
{
memset(dp,0,sizeof(dp));
dp[0]=1;
for(T=1;T<=60;T++)
{
a[T]=gen()%j+1;
for(int i=60;i>=a[T];i--)
dp[i]+=dp[i-a[T]];
if(dp[60]>n)
break;
m=n-dp[60],fl=T;;
// printf("%d\n",m);
for(int i=0;i<=29;i++)
id[i]=i;
sort(id,id+30,cmp);
for(int i=0;i<=29;i++)
{
while(fl<=60&&m>=dp[id[i]])
a[++fl]=60-id[i],m-=dp[id[i]];
}
if(!m&&fl<=60)
{
printf("%d\n",fl);
for(int i=1;i<=fl;i++)
printf("%d ",a[i]);
exit(0);
}
}
}
}
}
标签:le,int,30,Bundles,game,60,Game,CF1854E,dp
From: https://www.cnblogs.com/mekoszc/p/17742764.html