首页 > 其他分享 >CF2023D - Many Games

CF2023D - Many Games

时间:2024-11-10 14:45:49浏览次数:1  
标签:frac CF2023D int Many sum long times Games 100

HDK: 他妈的,这个看着也不像 2900 啊,为啥控我这么久

lbtl: 他不控你这么久不就不是 2900 了吗

暴力

一个比较明显的暴力思路是,如果我们钦定选定的物品的价值,那么可以比较容易地由背包 DP 算出能达到这个钦定值的最大概率

从 \([0,\sum w_i]\) 枚举所有可能的价值,暴力跑若干次背包,可以通过高达六个测试点

暴力
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int p[200001],w[200001];
long double f[200001];
signed main(){
    cin>>n;
    int totw=0;
    for(int i=1;i<=n;++i){
        cin>>p[i]>>w[i];
        totw+=w[i];
    }
    long double ans=0;
    for(int i=1;i<=totw;++i){
        for(int j=0;j<=i;++j){
            f[j]=0;
        }
        for(int j=1;j<=n;++j){
            for(int k=i;k>=w[j];--k){
                f[k]=max(f[k],f[k-w[j]]*p[j]/100.0);
            }
            f[w[j]]=max(f[w[j]],(long double)p[j]/100.0);
        }
        ans=max(ans,f[i]*i);
    }
    printf("%.8Lf",ans);
}

优化

一个比较 naive 的优化是,你发现你根本就不用钦定选定价值,直接跑一遍背包就能把所有答案跑出来,但是因为太 naive 了,仍然只有六个测试点的高分

第一个优化是对我们枚举上界的优化

推一遍式子,考虑设当前 \(\sum \frac{p_i}{100}=x,\sum w_i=y\)

当加入物品 \((p,w)\) 时对答案有正贡献,当且仅当

\[\begin{aligned}xy&\lt x\times \frac{p}{100}\times (y+w)\\y&\lt \frac{p}{100}(y+w)\\(1-\frac{p}{100})y&\lt\frac{p}{100}w\\y&\lt\frac{pw}{100-p}\end{aligned} \]

由于题目规定 \(pw\le 2\times 10^5\),而 \(100-p\) 的下界是 \(1\),因此加入物品 \((p,w)\) 时对答案有正贡献的一个必要条件是 \(\sum\limits w_i\le 2\times 10^5\)

这样我们就将答案区间 从 \([0,\sum w_i]\) 降到 \([0,2\times 10^5]\) 了

但是

喜报,复杂度还是不对

我们再考虑其他两个优化

第二个优化是,我们贪心地想,选择 \(p_i=100\) 的 \(i\) 一定是最优的,因此我们可以提前将 \(p_i=100\) 的 \(i\) 全部选上,这样既压缩了答案区间也减少了物品数量

第三个优化是,我们观察剩下的 \(p_i\neq 100\) 的物品,如果我们将 \(p_i\) 相同的 \(i\) 分成同一组,并且让每一组内按照 \(w_i\) 降序排列,根据贪心思路,当 \(p\) 相同的时候,应该是 \(w\) 越大越好,最终答案一定是形如从每个 \(p_i\) 的组内选出一个前缀

和刚才的思路类似,现在我们钦定我们选择的物品的 \(p_i\) 都为 \(p\),如果我们给当前 \(p\) 选择的前缀长度从 \(k\) 增加到 \(k+1\),答案更优当且仅当(这里挂 \(100\) 太麻烦了,在下面几个式子里钦定 \(p=\frac{p_i}{100}\))

\[\begin{aligned}p^k\times \sum\limits_k w\lt p^{k+1}\times(w_{k+1}+\sum\limits_k w)\end{aligned} \]

由于新加入的 \(w_{k+1}\) 不大于已有的任何一个数,因此有 \(k\times w_{k+1}\le\sum\limits_k w_i\),因此

\[\begin{aligned}p^k\times \sum\limits_k w&\le p^{k+1}\times\frac{k+1}{k}\times\sum\limits_k w_i\\\frac{k+1}{k}&\lt p\\k+1&\lt k\times p\\k\lt \frac{1}{1-p}\end{aligned} \]

这个式子意味着只有前 \(\frac{1}{1-p}\) 个物品有可能成为最优解

赛时止步于只写了两个优化,并且发现了最后那个先增后减的单调性,但是没总结出最后一个结论,比较可惜

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int p[200001],w[200001];
struct item{
    int w,p;
}a[200001];
int cnt=0;
long long orians;
long double f[200001];
long double ans;
vector<int>v[101];
signed main(){
    cin>>n;
    for(int i=1;i<=n;++i){
    	cin>>p[i]>>w[i];
    	v[p[i]].push_back(w[i]);
    	if(p[i]==100) orians+=w[i];
	}
    for(int i=1;i<=100;++i){
        sort(v[i].begin(),v[i].end(),greater<int>());
    }
	for(int i=1;i<=99;++i){
        int tot=0;
	    for(int j=0;j<=(int)v[i].size()-1;++j){
	    	if(tot>100/(100-i)) break; 
	    	a[++cnt]={v[i][j],i};
            tot++;
		}
	};
	f[0]=1;
	for(int i=1;i<=cnt;++i){
	    for(int j=200000;j>=a[i].w;--j){
	        f[j]=max(f[j],f[j-a[i].w]*a[i].p/100.0);
        }
    }
	for(int i=0;i<=200000;++i){
        ans=max(ans,f[i]*(orians+i));
    }
	printf("%.8Lf",ans);
}

标签:frac,CF2023D,int,Many,sum,long,times,Games,100
From: https://www.cnblogs.com/HaneDaCafe/p/18537949

相关文章

  • LINQ SelectMany的应用场景
     示例1:多层集合展平假设你有一个列表,每个元素都是一个字符串数组,你想将所有的字符串展平成一个单一的字符串列表。  示例2:嵌套循环假设你有一个用户列表,每个用户有一个订单列表,你想获取所有用户的订单列表。 示例3:多对多关系假设你有一个学生列表,每个学生选修......
  • 连接云虚拟主机中MySQL数据库时出现“Too many connections”报错信息
    在使用云虚拟主机过程中,当尝试连接MySQL数据库时,可能会遇到以下错误信息:  CannotconnecttoMySQLserverError:Toomanyconnections这表示MySQL数据库服务器当前的连接数已经达到了最大限制,无法处理更多的连接请求。可能原因应用程序未及时释放连接:应用程序在......
  • CF2023D Many Games
    题目大意有\(n\)个二元组\((p_i,w_i)\),保证\(1\lep_i\le100,p_iw_i\le200000\),求一个集合\(S\),使得\(\prod_{i\inS}\frac{p_i}{100}\sum_{i\inS}w_i\)最大\[n\le200000\]题解考虑一个极大的集合有什么样的性质,所谓极大就是不能够通过加入一个元素使得答案更大设集合为\(S......
  • CF2023D Many Games 题解
    赛时被创四了。思路考虑我们什么时候合并会比原来优。例如,我们现在要合并\(p_1,w_1\)和\(p_2,w_2\),同时保证,\(w_1\gew_2\)。那么有:\[\frac{p_1}{100}\timesw_1\le\frac{p_1}{100}\times\frac{p_2}{100}\times(w_1+w_2)\]\[\frac{p_2}{100}\timesw_2\le\frac{p_1}{......
  • CF2023 - D. Many Games
    先让\(p\)除以\(100\),相当于给你两个数组\(p,w\),然后要选择下标集合\(S\),使得:\(p\)的积乘上\(w\)的和最大化。注意到\(p_i\)是整数,并且\(1\lep_i\le100\)。那么容易想按照\(p_i\)分类。然后\(w_i\)对于固定\(p\)一定是选择排序后的最大值后缀。目前\((......
  • Educational Codeforces Round 170 (Rated for Div. 2) C. New Games
    题意转化找一些相邻的数(其中相邻定义为递增序下任意相邻两数差\(\leq1\))求相邻数中,不同数字有\(k\)种,取到数字个数的最大值算法容易想到按顺序排列观察到有点像滑动窗口,考虑用队列维护一个出现不同数字次数为\(k\)的区间,再计算代码来自转载地址voidsolv......
  • GAMES101(作业7)
     作业七题目:实现pathTracing,仅修改castRay(constRayray,intdepth)函数,在其中实现PathTracing算法代码框架://OBJ-loader模型加载库 global:全局变量/函数 vector:Vector3f,Vector2f类floatnorm(){returnstd::sqrt(x*x+y*y+z*z);}/*向量长度......
  • Too many / Not enough values in OpenAI Gym Mario Model for Reinforcement Learnin
    题意:在OpenAI Gym的马里奥兄弟(Mario)模型中,对于强化学习来说,存在“值太多”或“值不够”的问题问题背景:ReinforcementlearningusingOpenAIGymhastheabilitytomakeareinforcementmodelforplayingSuperMarioBros.ItrieddoingthisfollowingNicholasRe......
  • Codeforces Round 959 (Div. 1 + Div. 2) C. Hungry Games题解
    CodeforcesRound959(Div.1+Div.2)C.HungryGames题解题目链接大致题意:给定一个长度为n的数组,并且给出一对l,r表示一个区间,如果∑i......
  • ARC073F Many Moves
    当你填表法推了半年没推出来,为什么不试试刷表法呢?洛谷传送门在一行中有$n$个格子,从左往右编号为\(1\)到\(n\)。有\(2\)颗棋子,一开始分别位于位置\(A\)和\(B\)。按顺序给出\(Q\)个要求,每个要求是如下形式:给出一个位置\(x_i\),要求将两个棋子中任意一个移动到位置\(x......